您的位置:首页 > 其它

UVA 10529 浅谈期望动态规划末状态转移推导全方程转移

2017-09-19 17:50 387 查看


世界真的很大

UVA的数据好像其实很水

n^2/2的复杂度本来应该贴着边界的但是却跑的飞快

。。。

其实是有优化的,但是优化和这道题本身就没什么关系了

只是DP单峰函数的性质在作祟而已,不必写他

考虑期望这种东西如果顺退很难想的话,考虑最后一步的状态转移是不是确定的,如果是就可以考虑怎么从最后一步转移,就是所谓的倒着推DP

就算倒着不好推,起码也可以得出转移方程

这道题就是如此

看题先:

description:

你正在尝试建立直立的多米诺骨牌,站立起来
最后,为了您的娱乐而被推迟。 (当然,
设置某些东西只是为了击倒它似乎毫无意义
再次,但你有一些奇怪的爱好)棘手的事情
关于设置多米诺骨牌,但是,如果你犯了一个错误
在你放置它的时候敲一下,它会击倒任何一个
其一侧的连续多米诺骨牌的相邻线,部分
毁了你的工作
例如,如果你已经把多米诺骨牌放在了pat-
tern`DD DxDDD D,你尝试把一个多米诺骨牌放在位置
“x”,有一个机会,它将跌倒,敲多米诺骨牌
左边或三个多米诺骨牌右边,迫使你放下
他们再次
这个人为错误有点不可避免,但是你可以
通过使用多米诺骨牌,
放置技术,导致多米诺骨牌落在一个方向,
比其他更频繁。
考虑到您正在尝试建立的多米诺骨牌数量
你会击倒任何一个多米诺骨牌的可能性
放在左边或者右边,确定
你需要放置的平均多米诺骨牌数量
你没有假设您使用的是最佳的投放策略


input:

输入最多可达100例。 每个案例由一行输入组成。 它将包含的数量
多米诺骨牌去,n,1? n? 1000,其次是非负值P1和Pr,表示概率
任何多米诺骨牌在左边向右撇下。 你可以假设0 <P1 + Pr?0:5。
最后一个测试用例之后是一个包含单个“0”的行。


output:

对于每种情况,输出在你吃完之前需要放置的预期的多米诺骨牌数量,
精确到小数点后的两位数字。


题面来自谷歌翻译

百度翻译的题面真的不能看

考虑Ei表示放了连续的i块的最小期望值,思考一下怎么转移

一步一步来推的话还是比较难,考虑i是最后一步,那么i肯定是填上了一个空位,就是说,当i放的时候,左右两边都已经放好连续的一堆了,设左边一堆的期望次数是E1,右边一堆的期望值是E2

那么首先,Ei=E1+E2+1,这是废话

但是还需要考虑向左倒的情况,这时就不得不重新把左边的放一边,然后又到了现在的局面,还是需要Ei步,但是不用放右边了,一位没有向右边到,就不需要E2,那么还需要Ei-E2步,期望就是pl*(Ei-E2)

同理向右倒就是pr*(Ei-E1)

那么Ei=E1+E2+1+pl * (Ei-E2)+pr * (Ei-E1)

左右移一下项就就是:Ei=E1 * (1-pr)/(1-pl-pr)+E2 * (1-pl)/(1-pl-pr)+1/(1-pl-pr)

然后枚举左右的块数取一个min就可以递推了

Ei=min(Ej * (1-pr)/(1-pl-pr)+E

i-1-j * (1-pl)/(1-pl-pr)+1/(1-pl-pr))

n^2递推

完整代码:

#include<stdio.h>
#include<algorithm>
using namespace std;

const double INF=0x3f3f3f3f;

int n;
double pl,pr,f[1000010];

int main()
{
while(1)
{
scanf("%d",&n);
if(!n) return 0;
scanf("%lf%lf",&pl,&pr);
for(int i=1;i<=n;i++)
{
f[i]=INF;
for(int j=0;j<i;j++)
f[i]=min(f[i],f[j]*(1-pl)/(1-pl-pr)+f[i-1-j]*(1-pr)/(1-pl-pr));
f[i]+=1/(1-pl-pr);
}
printf("%0.2lf\n",f
);
}
return 0;
}
/*
Whoso pulleth out this sword from this stone and anvil is duly born King of all England
*/


嗯,就是这样
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: