【POJ2151】Check the difficulty of problems
题意
某场比赛有M道问题,T支队伍,和数字N给出每支队伍解决每道问题的概率。 问这场比赛满足下面两个条件的概率
1.每支队伍至少做出一道题
2.冠军队至少做出N道题。
分析
条件2是不是可以转化为 至少有一支队做出N道及以上道题。
这个题主要是概率,其次才是dp,而且好像不算概率DP。
我们来倒推一下。
设p2为每支队伍做出来的题数都在(1-N-1)的概率。p1为每只队伍至少做出来一道题的概率。那么答案就是p1-p2。
然后我们再来想怎么求p1和p2。设s[i][j]为第i支队伍做出来题数小于等于j的概率。那么
p1=(1-s[1][0])*(1-s[2][0])*...*(1-s[T][0]).
p2=(s[1][N-1]-s[1][0])*(s[2][N-1]-s[2][0])*...*(s[T][N-1]-s[T][0])。
然后再往前推。s[i][j]该怎么求?
我们发现队伍与队伍之间没有关系,于是我们可以每支队伍都通过dp求解。对于每支队伍k
我们令f[i][j]为前i个问题中做出来j个题的概率 f[i][j]=f[i-1][j]*(1-P[k][j])+f[i-1][j-1]*P[k][j];
然后 s[k][j]=sum(f[M][l])(0<=l<=j)
就是这个样子。
这个题的DP是最基础的,但是概率那里我觉得不是特别好想。。(可能因为我菜吧···)
1 #include <cstdio> 2 #include <cstring> 3 #include <iostream> 4 #include <algorithm> 5 6 using namespace std; 7 const int maxn=1000+100; 8 const int maxm=50; 9 int M,T,N; 10 double P[maxn][maxm]; 11 double f[maxm][maxm],s[maxn][maxm]; 12 int main(){ 13 while(scanf("%d%d%d",&M,&T,&N)!=EOF&&(M||T||N)){ 14 memset(P,0,sizeof(P)); 15 for(int i=1;i<=T;i++){ 16 for(int j=1;j<=M;j++){ 17 scanf("%lf",&P[i][j]); 18 } 19 memset(f,0,sizeof(f)); 20 f[0][0]=1.0; 21 for(int j=1;j<=M;j++){ 22 for(int k=0;k<=j;k++){ 23 if(k==0) 24 f[j][k]=f[j-1][k]*(1-P[i][j]); 25 else 26 f[j][k]=f[j-1][k-1]*P[i][j]+f[j-1][k]*(1-P[i][j]); 27 } 28 } 29 double sum=0; 30 for(int j=0;j<=M;j++){ 31 sum+=f[M][j]; 32 s[i][j]=sum; 33 } 34 } 35 double p1,p2; 36 p1=p2=1.0; 37 for(int i=1;i<=T;i++){ 38 p1*=(1-s[i][0]); 39 } 40 for(int i=1;i<=T;i++){ 41 p2*=(s[i][N-1]-s[i][0]); 42 } 43 double ans=p1-p2; 44 printf("%.3f\n",ans); 45 } 46 return 0; 47 }