hdu1203 I NEED A OFFER!---概率DP(01背包)

题目链接:

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 }
 
原文地址:https://www.cnblogs.com/fzl194/p/8676716.html