注解
1、此题是0/1背包,或者叫完全背包,每个物品最多只有1个,选或不选,在给定容量前提下,使得收益最大。
2、将输入的学校和概率分别用两个数组存储(也可以用一个结构体)。要计算至少得到一份offer的最大概率,反面算,就是用1减去一个offer都没有的最小概率。一个offer都没有,就是每个offer都没获得的概率的连乘。因此初始化的时候就用prob[i] = 1.0 - prob[i];,数组内存储的就是未获得该offer的概率。
3、背包求最优解,从前往后计算或者从后往前计算应该都是可行的,但是要注意不要暴力循环!本题的做法是m所学校,因此第一重循环是0到m,第二层循环初始值是n,也就是拥有的最大费用,循环条件的终止点是第i个学校的费用(只有当前费用>=第i所学校的费用时,才能申请该学校啊),循环体内就一句话,这个学校选还是不选,求概率的最小值。
//m个offer
for(int i=0; i<m; i++) {
//从后往前依次计算最小值
for(int j=n; j>=pos[i]; j--) {
//选和不选,两种情况,取最小值
minProb[j] = min(minProb[j], minProb[j-pos[i]]*prob[i]);
}
}
4、计算的是未被录取的概率,输出要取反。另外要输出百分比(注意百分号如何输出),且保留一位小数。
代码
#include <iostream>
using namespace std;
int main() {
int n, m;
scanf("%d %d", &n, &m);
while(n || m) {
int pos[m];
double prob[m];
for(int i=0; i<m; i++) {
scanf("%d %lf", &pos[i], &prob[i]);
//反面考虑:至少有一个offer的反面就是一个offer都没有
prob[i] = 1.0 - prob[i];
}
double minProb[n+1];
for(int i=0; i<n+1; i++) {
minProb[i] = 1.0;
}
//m个offer
for(int i=0; i<m; i++) {
//从后往前依次计算最小值
for(int j=n; j>=pos[i]; j--) {
//选和不选,两种情况,取最小值
minProb[j] = min(minProb[j], minProb[j-pos[i]]*prob[i]);
}
}
printf("%.1lf%%\n", 100.0 * (1.0-minProb[n]);
scanf("%d %d", &n, &m);
}
return 0;
}