[dp][概率与期望dp]Dumb Bones

UVA10529(洛谷)

【题目描述】

你正在尝试用多米诺骨牌搭成一条直线,以便最后试验时推倒它们

(确实,搭建某些东西仅仅为了推倒看上去没啥意义,但你有一些奇怪的爱好)

然而你在搭建过程中可能会弄倒骨牌,这将波及到邻近的部分

现在需要你来求将骨牌搭建完成所需的期望步数

【输入】

若干组数据,以0结尾

一个整数n(1 \leq n \leq 1000)(1≤n≤1000) 表示你需要搭的骨牌数量

两个整数P_l,P_rPl​,Pr​ 分别表示搭建某个骨牌时向左,向右倾倒的概率

【输出】

对于每组数据,输出一个实数,保留两位小数,为搭建完成的期望步数

【样例输入】

10 0.25 0.25
10 0.1 0.4
10 0.0 0.5
0

【样例输出】

46.25
37.28
20.00

分析:

期望是什么?
概率与期望dp+区间dp
题面与区间dp类似。设 E [ i ] E[i] E[i]表示前i块骨牌搭建完成的期望步数。
因此,对于前i块骨牌,可以考虑当前放第j块骨牌,该骨牌左侧骨牌摆好的期望值为 E [ j ] E[j] E[j],右侧为 E [ i − j − 1 ] E[i-j-1] E[ij1];显然, E [ j ] E[j] E[j] E [ i − j − 1 ] E[i-j-1] E[ij1]互不影响

当前骨牌没有倒: 1 1 − p l − p r \frac{1}{1-pl-pr} 1plpr1
向左倒: p l ∗ E [ j ] 1 − p l − p r \frac{pl*E[j]}{1-pl-pr} 1plprplE[j]
向右倒: p r ∗ E [ i − j − 1 ] 1 − p l − p r \frac{pr*E[i-j-1]}{1-pl-pr} 1plprprE[ij1]
s o , E [ i ] = E [ j ] + E [ i − j − 1 ] + 1 1 − p l − p r + p l ∗ E [ j ] 1 − p l − p r + p r ∗ E [ i − j − 1 ] 1 − p l − p r so,E[i]=E[j]+E[i-j-1]+\frac{1}{1-pl-pr}+\frac{pl*E[j]}{1-pl-pr}+\frac{pr*E[i-j-1]}{1-pl-pr} so,E[i]=E[j]+E[ij1]+1plpr1+1plprplE[j]+1plprprE[ij1]
E [ i ] = m i n ( 1 1 − p l − p r + ( 1 − p r ) ∗ E [ k ] 1 − p l − p r + ( 1 − p l ) ∗ E [ i − k − 1 ] 1 − p l − p r ) ( 0 < = k < i ) E[i]=min(\frac{1}{1-pl-pr}+\frac{(1-pr)*E[k]}{1-pl-pr}+\frac{(1-pl)*E[i-k-1]}{1-pl-pr})(0<=k<i) E[i]=min(1plpr1+1plpr(1pr)E[k]+1plpr(1pl)E[ik1])(0<=k<i)

这样得到一个0(n2)的算法,观察状态转移方程第二项是不断增大的,第三项是减少的,
第一项是常数,则Ei是一个单峰函数,且是下凹的,可以用二分或三分来优化,复杂
度为O(n*logn)
又因为E数组是下凹的,利用这个性质,我们可以证明决策k是不减的,可以利用单调性来优化到O(n)的效率

代码:

#include<bits/stdc++.h>
using namespace std;
const int N=1e3+10;
double f[N],pl,pr;
int n;
double getdp(int i,int j){
	return f[j]+f[i-j-1]+(1+pl*f[j]+pr*f[i-j-1])/(1-pl-pr);
}
double solve(){
	for(int i=1,j=0;i<=n;i++){
		while(j<i-1&&getdp(i,j)>getdp(i,j+1)) j++;
		f[i]=getdp(i,j);
	}
	return f[n];
}
int main(){
	while(1){
		scanf("%d",&n);
		if(n==0) break;
		scanf("%lf%lf",&pl,&pr);
		printf("%.2lf\n",solve());
	}
	return 0;
}
  • 1
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 2
    评论
评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值