UVA10529 Dumb Bones
https://www.luogu.com.cn/problem/UVA10529
概率\(DP\)
若一件事发生的概率为\(p\),那么该事件发生的概率为\(\frac{1}{p}\)
达到骨牌不倒的期望次数为:
\[\frac{1}{1-pl-pr}
\]
所以骨牌倒的期望次数为:
\[\frac{1}{1-pl-pr}-1=\frac{pl+pr}{1-pl-pr}
\]
其中,向左倒的期望次数为:
\[\frac{pl+pr}{1-pl-pr}\times \frac{pl}{pl+pr}=\frac{pl}{1-pl-pr}
\]
向左倒了,左边必须重建,一开始建了一次,倒了\(\frac{pl}{1-pl-pr}\)次,需要建:
\[\frac{pl}{1-pl-pr}+1=\frac{1-pr}{1-pl-pr}
\]
\(So:\)
\[dp_i=\min_{1 \le j \le i}
\frac{1-pr}{1-pl-pr} \times dp_{j-1}+\frac{1-pl}{1-pl-pr} \times dp_{i-j} +\frac{1}{1-pl-pr}
\]
\(Code:\)
#include<cstdio>
#include<iostream>
#include<algorithm>
#define D double
#define N 1005
using namespace std;
int n;
D k1,k2,k3,pl,pr,dp[N];
int main()
{
for (;'G'!='K';)
{
scanf("%d",&n);
if (!n)
break;
scanf("%lf%lf",&pl,&pr);
D k1=(1.0-pr)/(1-pl-pr);
D k2=(1.0-pl)/(1-pl-pr);
D k3=1.0/(1-pl-pr);
for (int i=0;i<=n;i++)
dp[i]=12345678987.0;
dp[0]=0.0;
for (int i=1;i<=n;i++)
for (int j=1;j<=i;j++)
dp[i]=min(dp[i],k1*dp[j-1]+k2*dp[i-j]+k3);
printf("%.2lf\n",dp[n]);
}
return 0;
}
还可以利用决策单调性优化到\(O(n)\)
\(C++ Code:\)
#include<cstdio>
#include<iostream>
#include<algorithm>
#define D double
#define N 1005
using namespace std;
int n;
D k1,k2,k3,pl,pr,dp[N];
int main()
{
for (;'G'!='K';)
{
scanf("%d",&n);
if (!n)
break;
scanf("%lf%lf",&pl,&pr);
D k1=(1.0-pr)/(1-pl-pr);
D k2=(1.0-pl)/(1-pl-pr);
D k3=1.0/(1-pl-pr);
for (int i=0;i<=n;i++)
dp[i]=12345678987.0;
dp[0]=0.0;
int k=0;
for (int i=1;i<=n;i++)
{
dp[i]=k1*dp[k-1]+k2*dp[i-k]+k3;
while (k+1<=i && k1*dp[k]+k2*dp[i-k-1]+k3<dp[i])
{
dp[i]=k1*dp[k]+k2*dp[i-k-1]+k3;
k++;
}
}
printf("%.2lf\n",dp[n]);
}
return 0;
}