最近主要刷一下动态规划专题,题目来自于HDU。
这是一道概率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日
【未完待续...】
原文:http://www.cnblogs.com/Ivy-End/p/4337406.html