题意
有一个百万富翁被困在城堡里,有n个走廊通向外面。这n个走廊有两个属性值p[i],q[i] 分别表示在这条走廊成功走出去的几率和遇见士兵的几率,如果遇见士兵的话,就需要给他1万元,然后返回承包,还有(1-p[i]-q[i])的几率走廊是个死胡同,不能出去,然后就会走回城堡。
现在已知这个百万富翁携带有m万元,求逃出的概率。
分析
首先发现这个富翁一定会贪心的走走廊。具体怎么贪心呢。就是走成功逃出几率大而且被抓概率小的走廊。成功脱出的概率是p/(p+q)化简一下去掉常数就是p/q 所以按这个东西排序即可。
然后是往DP上想。
状态的定义
dp[i][j]表示还剩下j万元,活着走出第i条走廊的概率。
答案是什么
初始化
dp[0][0]=1.0 剩下的都赋值为0。
状态转移方程
对于任意一个状态[i,j],都会往三种状态转移
p[i+1]的概率逃出:res+=p[i+1]*dp[i][j]
q[i+1]的概率被抓:dp[i][j-1]+=q[i+1]*dp[i][j] {j>0}
1-p[i+1]-q[i+1]的概率什么都没发生,回来:dp[i+1][j]+=(1-p[i]-q[i])*dp[i][j]
code
#include<cstdio>
#include<algorithm>
#include<cstring>
using namespace std;
void Max(double &x,double y){if (x<y)x=y;}
struct AC{double p,q;}a[1005];
double dp[1005][12];
bool cmp(AC a,AC b){return a.p*b.q>b.p*a.q;}
int main(){
int t,n,m,i,j;
scanf("%d",&t); int cnt=0;
for (; t; t--){
scanf("%d%d",&n,&m);
for (i=1; i<=n; i++)scanf("%lf%lf",&a[i].p,&a[i].q);
sort(a+1,a+n+1,cmp);
double res=0;
memset(dp,0,sizeof(dp)); dp[0][0]=1;
for (i=1; i<=n; i++){
for (j=0; j<=m; j++){
res+=dp[i-1][j]*a[i].p;
dp[i][j+1]+=dp[i-1][j]*a[i].q;
dp[i][j]+=dp[i-1][j]*(1-a[i].q-a[i].p);
}
}
printf("Case %d: ",++cnt);
printf("%.5f\n",res);
}
return 0;
}
反思
其实这个大概还是好想的,不过一开始写的时候没有想到贪心的走…然后卡了很久。非要说的话这题就是贪心+概率Dp这样的…?
大概还是要多分析分析题目….这样。
我太菜了….