01背包,价值是概率连乘。
首先,给的都是某学校被录取的概率,问的是总体被录取的最大概率,所以要转化为都不被录取的最小概率。
dp[j]
表示(在前i
个学校可选取的情况下,)使用的申请费总额不超过j
的情况下不被任何一家录取的最小概率。
所以初始的dp
值都是1.0
。
本题和HDU 2955的区别在于,前者求最小概率,后者求最大概率。因而要采取不同的策略:
- 本题:因为价值是概率连乘,只会越来越小,而且是求解最小价值(最小概率),两者的方向一致。所以无需限制恰好装满。只需要把所有
dp[]
初始为1.0
就可以了。 - HDU 2955:是求最大概率,两者的方向不一致。所以要限制恰好装满,否则
dp
值不会被更新。需要把初始时唯一的合法状态dp[0]
设为合法值1.0
,其余都设为非法值0.0
。
以上策略与普通01背包(价值是相加)是相反的。
#include <cstdio>
#include <iostream>
#include <algorithm>
#include <vector>
#include <cstring>
#include <string>
#include <queue>
using namespace std;
int N, M;
int w[10001];
double p[10001];
double dp[10001];
void init()
{
for (int i = 0; i <= M; i++)
dp[i] = 1.0;
}
int main()
{
for (; ~scanf("%d%d", &M, &N);)
{
if (M == 0 && N == 0) break;
init();
for (int i = 1; i <= N; i++)
{
scanf("%d%lf", &w[i], &p[i]);
p[i] = 1.0 - p[i];
}
for (int i = 1; i <= N; i++)
for (int j = M; j >= w[i]; j--)
dp[j] = min(dp[j], dp[j - w[i]] * p[i]);
printf("%.1lf%%\n", (1.0 - dp[M])*100.0); // 怎么输出'%'? "%%"
}
return 0;
}