最近主要刷一下动态规划专题,题目来自于HDU。
HDU 2955
这是一道概率DP,我第一次的想法是把概率P乘以100,变成一个背包然后做0-1背包,后来发现这样做是错误的。
原因:概率应该是相乘,而不是相加。
后来看了题解想到了另外一种方法,使用逃脱概率来计算,用f[j]表示偷走j价值后逃脱的概率。易知,多次逃脱概率为每次逃脱概率相乘。
由于要计算逃脱概率,我们可以在读入的时候就把可能被逮捕的概率P变成可能逃脱的概率1 - P。
这样,状态转移方程为:f[j] = max(f[j - pValue[i]] * pCost[i], f[j])。其中pValue[i]表示第i个银行的价值,pCost[i]表示偷第i个银行逃脱的概率。
这时候,我们还需要考虑一个转移条件,如果f[j - pValue[i]]没有被更新过,那么是不能转移过来的。因为暂时没有一个状态可以偷到j - pValue[i]价值的物品。
接下来,我们要考虑一下初始条件,很显然f[0] = 1,因为不偷任何东西,就不会被逮捕,逃脱的概率就为1。其余f[j] = -1,其中j ≠ 0,表示暂时没有一个状态可以偷到j价值的物品。
最后扫一遍f[j],满足1 - f[j] <= P的最大下标j为满足题设条件的答案。
#include <iostream> #include <memory.h> using namespace std; const int MAX = 10240; int pValue[MAX]; double pCost[MAX], f[MAX]; int main() { int T, M, V; double P; cin >> T; for(int k = 1; k <= T; k++) { f[0] = 1; V = 0; for(int i = 1; i < MAX; i++) { f[i] = -1; } cin >> P >> M; for(int i = 1; i <= M; i++) { cin >> pValue[i] >> pCost[i]; pCost[i] = 1 - pCost[i]; V += pValue[i]; } for(int i = 1; i <= M; i++) { for(int j = V; j >= pValue[i]; j--) { if(f[j - pValue[i]] != -1) { f[j] = max(f[j - pValue[i]] * pCost[i], f[j]); } } } int ans = 0; for(int i = 0; i <= V; i++) { if(1 - f[i] <= P) { ans = i; } } cout << ans << endl; } return 0; }
接触的第一道概率DP,发现DP非常的灵活,自己还有很多东西要学。
2015年3月14日
【未完待续...】
时间: 2024-10-07 09:45:45