(01揹包)hdu 2955 Robberies
阿新 • • 發佈:2021-02-08
題目
hdu2955
題意:
給出 n 家銀行的金額和被抓的概率,求出不超出被抓概率 p 的最大搶劫金額。
思路:
如果把被抓概率看成揹包容量進行dp,則wa,
這裡犯了一個常識的錯誤,被抓概率 = 被抓概率1 + 被抓概率2,其實這是錯的。
舉個例子,某彩票的中獎概率是50%,按照上面的計算方法(中獎概率 = 中獎概率1 + 中獎概率2),那麼買兩張彩票則必中獎(兩張彩票中獎概率 = 50% + 50% = 100%),這是不科學的。
實際上兩張彩票中獎概率為75%(兩張彩票中獎概率 = 第一張中第二張不中 + 第一張不中第二張中 + 兩張都中 => 第一張中獎概率 * 第二張不中獎概率 + 第一張不中獎概率 * 第二張中獎概率 + 第一張中獎概率 * 第二張中獎概率 = 50% * 50% + 50% * 50% + 50% * 50% = 75%)
回到題目,也就是說,
被抓概率 = 第一家銀行被抓概率 * 第二家銀行不被抓概率 + 第一家銀行不被抓概率 * 第二家銀行被抓概率 + 第一家銀行被抓概率 * 第二家銀行被抓概率 => 1 - 第一家銀行不被抓概率 * 第二家銀行不被抓概率
因為被抓概率不是線性的,所有要把金額看成揹包容量進行dp,dp陣列記錄的是不被抓的最大概率。
程式碼
#include <bits/stdc++.h>
#define DEBUG freopen("_in.txt", "r", stdin); freopen("_out1.txt", "w", stdout);
#define CASE int t; cin >> t; while (t--)
using namespace std;
const int MAXN = 110;
const int MAXM = 1e4 + 10;
int v[MAXN];
double dp[MAXM], b[MAXN];
void solve(){
int n, tot = 0;
double p;
scanf("%lf%d", &p, &n);
for (int i = 0; i < n; i++){
scanf("%d%lf", & v[i], &b[i]);
b[i] = 1 - b[i];
tot += v[i];
}
memset(dp, 0, sizeof(dp));
dp[0] = 1; //一開始當然不會被抓
double temp;
for (int i = 0; i < n; i++)
for (int j = tot; j >= v[i]; j--)
dp[j] = max(dp[j], dp[j-v[i]] * b[i]);
for (int i = tot; i >= 0; i--)
if (1 - dp[i] <= p){ //輸出不被抓的最大金額
printf("%d\n", i);
break;
}
}
int main(){
CASE solve();
return 0;
}