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;
}