hdu 2955 Robberies
这道题自己写得挺久,最坑的一点是自己一开始是用 StreamTokenizer 类读取的,但是一直错,后来用 Scanner 类读取就 accept 了,搞不懂。
解这道题有以下关键点:
第一:一开始想的是用概率来作为背包容量,但是概率是浮点数,所以只能用钱来作为背包容量。
第二:题目中给出的都是被抓的概率,概率之间应该是相乘而不是相加,与一般的01背包不一样。
第三:dp[0] 注意初始化为 1, 什么都不偷逃跑的概率为 1。
import java.io.IOException;
import java.util.Scanner;
/**
* @author wangshaoyu
*/
public class Hdu2955robberies {
public static void main(String[] args) throws IOException {
Scanner in = new Scanner(System.in);
// 开始一维
int t = in.nextInt();
for (int i = 0; i < t; i++) {
double p = in.nextDouble(); // 总的被抓的概率
int n = in.nextInt(); // n banks
p = 1 - p; // 逃跑的概率
int totalMoney = 0; // 所有银行的总钱数
int[] money = new int[n];
double[] pi = new double[n]; // 被抓概率
for (int j = 0; j < n; j++) {
money[j] = in.nextInt();
totalMoney += money[j];
pi[j] = in.nextDouble();
}
// 前i个银行偷到j能够逃跑的概率
double[] dp = new double[totalMoney+1];
dp[0] = 1; // 什么都不偷不被抓概率为 1
for (int j = 0; j < n; j++) {
for (int k = totalMoney; k - money[j] >= 0; k--) {
// 注意:是乘法不是加法,古典概型
dp[k] = Math.max(dp[k], dp[k - money[j]] * (1 - pi[j]) ); // 题目给出的是偷每个银行被抓的概率,所以需要用1去减得到 逃跑概率
}
}
for (int j = totalMoney; j >= 0; j--) {
// 能够逃跑的概率必须大于最低的逃跑概率
if (dp[j] >= p) {
System.out.println(j);
break;
}
}
}
}
}