链接:http://acm.hdu.edu.cn/showproblem.php?pid=4815
【题意】
n个题目,每题有各自的分数,A有50%的概率答对一道题目得到相应分数,B想要在至少P的概率上总分不低于A,问B至少要得到多少分。
【分析】
最简单粗暴的做法是算出每个可能得到的总分的概率,原问题可以转化成在概率和<=P下A所有可能得到的总分集合中最大分数的最小值为多少,于是答案就是按分数排序后前k项的概率和刚好>=P。
但是计算所有可能的概率的复杂度是O(2n),不能满足我们的需求。细心分析可以发现问题可以分离出重叠子问题:f[i][j]表示前i个题目得到j分数的概率,于是类似背包问题,可以找出递推式:
f[i][j]=f[i-1][j]*0.5 (score[i]>j)
f[i][j]=f[i-1][j-score[i]]*0.5+f[i-1][j]*0.5 (score[i]<=j)
于是问题就解决了。
【代码】
1 //by wuminye 2 #include <stdio.h> 3 #include <string.h> 4 int data[41]; 5 double dp[40001]; 6 int main() 7 { 8 int T; 9 scanf("%d",&T); 10 while (T--) 11 { 12 int n,sum=0; 13 double p; 14 scanf("%d%lf",&n,&p); 15 for (int i=0;i<n;++i) 16 { 17 scanf("%d",data+i); 18 sum+=data[i]; 19 } 20 memset(dp,0,(sum+1)*sizeof(double)); 21 dp[0]=1; 22 for (int i=0;i<n;++i) 23 for (int j=sum;j>=0;--j) 24 { 25 if (data[i]>j) dp[j]*=0.5; 26 else dp[j]=dp[j-data[i]]*0.5+dp[j]*0.5; 27 } 28 for (int i=0;i<=sum;++i) 29 { 30 p-=dp[i]; 31 if (p<=1e-6) {printf("%d ",i); break;} 32 } 33 } 34 }