题目链接
UvaLive 6441 Horrible Quiz
题意:有n个题目,现在A要一个一个的做,告诉你A做对第i题概率ci,做错的概率wi,还有1-ci-wi的概率他完全没有想法。初始的时候A有15000的积分,如果他答对一道题积分不变,答错一道题积分乘以-1(对就是这么扯淡)。如果一道题他完全没有想法他会去问B怎么做,B知道所有题的正解,但是B可能告诉A正解也可能告诉他错误的答案,还有个限制B最多只能给A说M次错误答案。问A最后积分的期望值中最低的为多少?
A最后得分的期望值其实掌握在B手里,而B会有很多种可行的策略,容易想到用动态规划求解。
dp【i】【j】表示前i个题目,B告诉了A j 次错误的答案,A积分的期望最小值。那么转移就是dp【i】【j】=min(dp【i-1】【j】*(1-2*wi),dp【i-1】【j-1】*(2*ci-1))。
但是这个转移方程是有问题的,因为1-2*wi和2*ci-1的正负不确定,所以我们还要开一维状态,dp【i】【j】【0】表示当前状态的最小值,dp【i】【j】【1】表示当前状态的最大值。那么转移的时候根据(1-2*wi)和(2*ci-1)的正负在前面转移的基础做一些修改就行了。代码如下:
#include<iostream> #include<stdio.h> #include<string.h> #include<algorithm> using namespace std; #define INFF 1e20 double dp[1300][1300][2]; double c[1300]; double w[1300]; double Min(double x,double y) { return x<y?x:y; } double Max(double x,double y) { return x>y?x:y; } int main() { int T,ncase=0; scanf("%d",&T); int i,j; int n,m; while(T--) { scanf("%d %d",&n,&m); for(i=0;i<=n;i++) for(j=0;j<=m;j++) { dp[i][j][1]=-INFF; dp[i][j][0]=INFF; } for(i=1;i<=n;i++) { scanf("%lf",&c[i]); c[i]=c[i]/100.0; } for(i=1;i<=n;i++) { scanf("%lf",&w[i]); w[i]=w[i]/100.0; } dp[0][0][0]=15000.0; dp[0][0][1]=15000.0; for(i=1;i<=n;i++) { for(j=0;j<=i&&j<=m;j++) { if(dp[i-1][j][0]!=INFF) { dp[i][j][0]=Min(dp[i][j][0],dp[i-1][j][0]*(1.0-w[i])-dp[i-1][j][0]*w[i]); dp[i][j][1]=Max(dp[i][j][1],dp[i-1][j][0]*(1.0-w[i])-dp[i-1][j][0]*w[i]); } if(dp[i-1][j][1]!=-INFF) { dp[i][j][1]=Max(dp[i][j][1],dp[i-1][j][1]*(1.0-w[i])-dp[i-1][j][1]*w[i]); dp[i][j][0]=Min(dp[i][j][0],dp[i-1][j][1]*(1.0-w[i])-dp[i-1][j][1]*w[i]); } if(j>0) { if(dp[i-1][j-1][0]!=INFF) { dp[i][j][1]=Max(dp[i][j][1],dp[i-1][j-1][0]*c[i]-dp[i-1][j-1][0]*(1.0-c[i])); dp[i][j][0]=Min(dp[i][j][0],dp[i-1][j-1][0]*c[i]-dp[i-1][j-1][0]*(1.0-c[i])); } if(dp[i-1][j-1][1]!=-INFF) { dp[i][j][1]=Max(dp[i][j][1],dp[i-1][j-1][1]*c[i]-dp[i-1][j-1][1]*(1.0-c[i])); dp[i][j][0]=Min(dp[i][j][0],dp[i-1][j-1][1]*c[i]-dp[i-1][j-1][1]*(1.0-c[i])); } //dp[i][j]=Min(dp[i][j],dp[i-1][j-1]*(1-w[i])-dp[i-1][j-1]*w[i]); } // printf("%lf .. ",dp[i][j][0]); } printf("\n"); } double ans=INFF; for(i=0;i<=m;i++) ans=Min(ans,dp[n][i][0]); printf("Case #%d: %.3lf\n",++ncase,ans); } return 0; }