题目点我
题目大意:给了
N
个银行的钱
思路:01背包问题,一开始想把概率取对数做背包容量,发现行不通。要用收益当背包容量,用安全概率当作背包价值。状态转移方程如下:
dp[i][M]=max(dp[i−1][M],dp[i−1][M−Mi]⋅(1−Pi))
其中
dp[i][M]
表示,在前
i
个银行中选择一些,收益为
这道题的背包要恰好装满,所以开始要把
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <math.h>
#define INF -1
#define MAX 10010
#define NUM 105
double dp[MAX];
double max(double a, double b){
return a > b ? a : b;
}
void ZeroOnePack(double *f, int cost, double p, int vol){
for(int i = vol; i >= cost; i--)
f[i] = max(f[i], f[i - cost] * (1 - p));
}
int main(){
int T, N, i, M[NUM], MaxM = 0;
double P[NUM], Psafe;
scanf("%d", &T);
while(T--){
scanf("%lf %d", &Psafe, &N);
for(i = 0; i < N; i++){
scanf("%d %lf", &M[i], &P[i]);
MaxM = MaxM > M[i] ? MaxM : M[i];
}
for(i = 1; i < N * MaxM; i++)
dp[i] = INF;
dp[0] = 1; //没抢钱的安全概率 = 1
for(i = 0; i < N; i++)
ZeroOnePack(dp, M[i], P[i], N * MaxM);
for(i = N * MaxM; i >= 0; i--){
if(dp[i] >= (1 - Psafe)){
printf("%d\n", i);
break;
}
}
memset(dp, 0, sizeof(double)*MAX);
}
return 0;
}