UVA10529 Dumb Bones (完成度:40%)
题目链接:https://vjudge.net/problem/UVA-10529
知识点: 概率与期望,DP。
题目大意:
现要放置 \(n\) 个多米诺骨牌,且每放置一块多米诺骨牌有 \(P_l\) 的概率向左倒,其左边相邻的骨牌也会随之倒下;有 \(P_r\) 的概率向右倒,其右边相邻的骨牌同上。问要放置 \(n\) 块相连的一排骨牌所需要的放置次数的最小期望是多少?
\(1 \le n \le 100\)
\(0 < P_l + P_r \le 0.5\)
解题思路:
我们用动态规划的方法来解决这个问题。
设 \(dp(i)\) 为放置 \(i\) 块相连的一排骨牌所需要的放置次数的最小期望,我们先给出状态转移方程:
\(dp(i) = min\{ dp(i), \frac{dp(l) \cdot P_l + dp(r) \cdot P_r + 1}{1-P_l-P_r} + dp(l) + dp(r) \mid 0 \le l \le i, r = i-1-l \}\)
上式中,我用 \(l\) 表示放置第 \(i\) 块骨牌(即最后一块)的时候左边的相连的骨牌数,\(r\) 则表示右边的。我们可以用 \((l,r)\) 来表示我们放置最后一块骨牌的位置,则当我们在 \((l,r)\) 放置最后一块骨牌时,放置这 \(i\) 块连续的骨牌所需要的次数的期望为 \(E = E(i) + dp(l) +dp(r)\),我们事先已经知道了 \(dp(k) \{0 \le k < i\}\),故重点就在于求解 \(E(i)\) ,即放置第 i 块所需的放置次数的期望。首先,我们需要知道:每放置一块多米诺骨牌有 \(1 - P_l - P_r\) 的概率不会倒。接下来,我们分成如下三种情况来讨论:
1、放置一次即成功,有 \(1 - P_l - P_r\) 的概率。则放置次数的期望为:\(\frac{1}{1 - P_l - P_r}\) ;
2、放置以后向左倒,有 \(P_l\) 的概率。我们需要先将左边的骨牌放置好,我们需要放置成功 \(dp(l)\) 次,每一次的成功概率都为 \(1 - P_l - P_r\),则需要的次数的期望为 \(\frac{dp(l)}{1-P_l-P_r}\),当然,我们也不能忘了乘上 \(P_l\),则最终的期望值为:\(\frac{P_l \cdot dp(l)}{1-P_l-P_r}\);
3、放置以后向右倒同理。
于是,我们不难推出:
\(E = \frac{dp(l) \cdot P_l + dp(r) \cdot P_r +1}{1 - P_l - P_r} + dp(l) + dp(r)\) .
一切也就顺理成章了。
AC代码:
1 #include <iostream> 2 #include <cstdio> 3 4 using namespace std; 5 const int maxn=1010; 6 const double inf=0x7fffffff; 7 double dp[maxn]; 8 int main() 9 { 10 int n; 11 double pl,pr; 12 while(scanf("%d",&n)==1&&n){ 13 scanf("%lf%lf",&pl,&pr); 14 for(int i=1;i<=n;i++) dp[i]=inf; 15 dp[0]=0; 16 int l,r; 17 for(int i=1;i<=n;i++){ 18 for(l=0;l<i;l++){ 19 r=i-1-l; 20 dp[i]=min(dp[i],(dp[l]*pl+dp[r]*pr+1)/(1-pl-pr)+dp[l]+dp[r]); 21 } 22 } 23 printf("%.2lf\n",dp[n]); 24 } 25 return 0; 26 }
PS: 此题还有一种 \(O(nlog n)\) 和一种 \(O(n)\) 的算法,未完待续。