Robberies HDU - 2955 (01揹包 + 概率轉換)
阿新 • • 發佈:2018-11-19
01揹包問題牽扯到兩個基本的屬性: 容量和價值, 如果直觀的照搬01揹包問題的話, 那麼容量和價值應該是逃跑概率和錢數.
但因為概率是一個浮點數, 而且題目也沒有給定最小是幾位小數, 所以無法遍歷
那麼就只能把容量定義為可得到的金錢, dp[v] 即為安全的概率, 題中給出的是被抓的概率, 但因為如果用被抓的概率在初始化上會有些麻煩, 所以乾脆定義為不被抓, 也就是安全的概率反而比較簡單. 因為各個事件都是獨立的, 所以多個事件安全的概率要用乘法相乘
可得狀態轉移方程
狀態: dp[i][j]: 前i種物品中搶j元時不被抓的概率
dp[i][j] = max{dp[i-1][j], dp[i-1][j-m[i]] * p[i] | j >= m[i] }
優化一下空間, 即
dp[j] = max{dp[j], dp[j-m[i]] * p[i] | j >= m[i] }
注意這裡的P = 1-P
#include <cstdio> #include <iostream> #include <algorithm> #include <cstring> #include <string> #include <vector> #include <queue> #include <cmath> using namespace std; #define ms(x, n) memset(x,n,sizeof(x)); typedef long long LL; const LL maxn = 10010; const double eps = 1e-9; int n, m[maxn], sum; double P, dp[maxn], p[maxn];//搶到j元時不被抓的概率 int solve() { ms(dp, 0); dp[0] = 1.0; for(int i = 1; i <= n; i++) for(int j = sum; j >= m[i]; j--) dp[j] = max(dp[j], dp[j-m[i]]*p[i]); //概率 for(int i = sum; i >= 0; i--) if(dp[i] - P >= eps) return i; } int main() { int T; cin >> T; while(T--){ cin >> P >> n; sum = 0, P = 1.0-P; //sum為總價值, P為不被抓的概率 for(int i = 1; i <= n; i++){ cin >> m[i] >> p[i]; sum += m[i], p[i] = 1.0-p[i]; //總價值和不被抓的概率 } cout << solve() << endl; } return 0; }