题目链接:
http://acm.hdu.edu.cn/showproblem.php?pid=1203
题目大意:
Speakless很早就想出国,现在他已经考完了所有需要的考试,准备了所有要准备的材料,于是,便需要去申请学校了。要申请国外的任何大学,你都要交纳一定的申请费用,这可是很惊人的。Speakless没有多少钱,总共只攒了n万美元。他将在m个学校中选择若干的(当然要在他的经济承受范围内)。每个学校都有不同的申请费用a(万美元),并且Speakless估计了他得到这个学校offer的可能性b。不同学校之间是否得到offer不会互相影响。“I NEED A OFFER”,他大叫一声。帮帮这个可怜的人吧,帮助他计算一下,他可以收到至少一份offer的最大概率。(如果Speakless选择了多个学校,得到任意一个学校的offer都可以)。
思路:
首先,转化成对立事件来计算,至少得到一个offer的最大概率,其对立事件就是一个offer都没得到的最小概率。
这样可以转化成01背包去做了,dp[i][j]表示的是用j万美元从前i个学校中选择学校,一份offer都收不到的最小概率。若不选择第i个学校,则dp[i][j] = dp[i-1][j],若选择了
第i个学校,则第i个学校的不录取率是1-value[i],前i-1个学校的不录取率为dp[i-1][j-cost[i]],则有dp[i][j] = dp[i-1][j-cost[i]]*(1-value[i]),则转移式为:
dp[i][j] = min(dp[i-1][j],dp[i-1][j-cost[i]]*(1-value[i])),答案就是1-dp[m][n],这里由于m,n较大,所以利用滚动数组求解。
1 #include<cstdio> 2 #include<cstring> 3 #include<iostream> 4 #include<algorithm> 5 #include<string> 6 using namespace std; 7 typedef long long ll; 8 int cases; 9 int n, m; 10 const int maxn = 1e5 + 100; 11 double dp[maxn], v[maxn]; 12 int money[maxn]; 13 int main() 14 { 15 while(cin >> n >> m && (n + m)) 16 { 17 for(int i = 0; i < m; i++) 18 { 19 cin >> money[i] >> v[i]; 20 v[i] = 1.0 - v[i]; 21 } 22 for(int i = 0; i <= n; i++)dp[i] = 1.0; 23 for(int i = 0; i < m; i++) 24 { 25 for(int j = n; j >= money[i]; j--)dp[j] = min(dp[j], (dp[j - money[i]]) * v[i]); 26 } 27 dp[n] = 1 - dp[n]; 28 printf("%.1f%% ", dp[n] * 100); 29 } 30 return 0; 31 }