博客
关于我
强烈建议你试试无所不能的chatGPT,快点击我
Dumb Bones UVA - 10529[多米诺重构]
阅读量:6854 次
发布时间:2019-06-26

本文共 1293 字,大约阅读时间需要 4 分钟。

Dumb Bones

 

 

来自绿书p176 

题意

你试图把一些多米诺骨牌排成直线,然后推倒它们。但是如果你在放骨牌的时候不小心把刚放的骨牌碰倒了,它就会把相临的一串骨牌全都碰倒,而你的工作也被部分的破坏了。

比如你已经把骨牌摆成了DD__DxDDD_D的形状,而想要在x这个位置再放一块骨牌。它可能会把左边的一块骨牌或右边的三块骨牌碰倒,而你将不得不重新摆放这些骨牌。

这种失误是无法避免的,但是你可以应用一种特殊的放骨牌方法来使骨牌更多的向一个方向

分析

首先应该明确怎样找到最佳的摆放策略。我们可以考虑在位置i放最后一块骨牌。显然,i前面的i-1块骨牌和i后面的n-i块骨牌是互不影响的。所以我们假设摆放i-1块骨牌需要的次数平均是(或说期望是)E1,摆放n-i块骨牌需要的次数平均是E2。那么我们摆放了这两段之后,就要把最后一块放上。这时如果把左边的碰倒了,就只好重新摆放。右边的也是同样的道理。所以需要摆放的平均值(E)是:

E = E+ E +

这个式子的推导并不困难,方法之一就是应用方程的思想(参见后面介绍的概率—期望系统)。

既然得到了这个式子,我们就可以通过动态规划来得到最优的摆放方案。设Ei是摆放i块骨牌所需要的最少期望次数,那么状态转移方程是:

Ei ­= min{E+ Ei-1-k­ + } (0≤k≤i-1)

这样就得到了一个O(n2)的算法。根据题目中的数据规模,最大的运算量是100*1000= 108,虽然可以忍受,但是还是比较慢的,如果数据稍大一点就容易超时。

这就需要我们对动态规划进行优化。

这是一个1D/1D的动态规划,我们自然希望得到O(n)的算法,而这种优化一般都是通过动态规划的方程性质得到的。

观察动态规划的方程,我们可以发现,当k从0变化到i-1时第一项是不断增大的,第二项是不断减小的,第三项则是一个常数。因此整个函数一定是单峰的,这样就可以通过二分的方法进行优化,复杂度已经降到了O(nlogn)。而事实上,E这个数列不但是单增的,而且是凹的(如果PlPr=0就不凹也不凸,但是这不影响这里的讨论),通过这个性质我们还可以证明决策使用的k一定是不减的(证明很简单,略去)。这样通过记录上一次决策使用的k,就得到了一个(均摊的)O(n)的算法。

Select Code

#include
using namespace std;const int N=1e5+5;double pl,pr,f[N];int n;double get(int i,int k){ return ((1-pr)*f[k]+(1-pl)*f[i-k-1]+1)/(1-pl-pr);}int main(){ for(scanf("%d",&n);n;scanf("%d",&n)){ scanf("%lf%lf",&pl,&pr); for(int i=1,j=0;i<=n;i++){ for(;j

 

转载于:https://www.cnblogs.com/shenben/p/6740866.html

你可能感兴趣的文章
POJ1091 跳蚤
查看>>
DUBBO本地搭建及小案例 (转)
查看>>
RabbitMQ指南之二:工作队列(Work Queues)
查看>>
软件测试2019:第八次作业—— 缺陷管理(含缺陷管理工具的配置实验)
查看>>
Go:slice
查看>>
一个android应用开发的感悟
查看>>
Qt Clipboard剪贴板简单使用
查看>>
使用UIElement.AddHandler捕获已被处理的RoutedEvent
查看>>
12.21站立会议
查看>>
SQL server 统计数据库表数量和列出所有表名称
查看>>
遍历DOM树,过滤节点
查看>>
XAML实例教程系列 - XAML传递参数到值转换类实例
查看>>
Android 推门效果
查看>>
validation-api参数校验
查看>>
H5游戏接微信小游戏的支付,满满的都是坑!
查看>>
导数、偏导数、方向导数、梯度、梯度下降
查看>>
C# 获取MAC地址
查看>>
Samsung_tiny4412(驱动笔记01)----linux 3.5,U-Boot,Busybox,SD卡启动环境搭建
查看>>
Linux ldconfig
查看>>
Linux 更改ssh 端口
查看>>