http://acm.hdu.edu.cn/showproblem.php?pid=2955
题意是一个小偷去偷N家银行,给一个被抓到的概率标准,然后给出每家银行能偷的钱和被抓的概率,求在不被抓的情况下最多能偷到多少钱?
将F(i)表示偷i元钱的最大安全概率,然后就是一个01背包问题,状态转移方程式F(i)=max{F[i],F[i-money[j]]*(1-p[j])}
#include <iostream>
#include <cstdio>
#include <cstring>
using namespace std;
int m[110];
float p[110],f[10010];
int main()
{int t;
//freopen("E:\\in.txt","r",stdin);
cin>>t;
while(t--)
{memset(f,0,sizeof(f));
f[0]=1;
int n;
float pm;//状态转移方程f[i]=max{f[i],f[i-m[j]]*(1-p[j])}
scanf("%f%d",&pm,&n);
int sum=0;
for(int i=0;i<n;i++)
{
scanf("%d%f",&m[i],&p[i]);
sum+=m[i];//sum为一共有多少钱
}
int i,j;
for(i=0;i<n;i++)//01背包的两层循环,有n家银行,这边的钱相当于背包容量
for(j=sum;j>=m[i];j--)
if(f[j]<f[j-m[i]]*(1-p[i]))
f[j]=f[j-m[i]]*(1-p[i]);
for(i=sum;i>=0;i--)
if(f[i]>=1-pm)
{
printf("%d\n",i);
break;
}
}
return 0;
}
在01背包中,有两种做法。
一种是二维数组dp[i][j]表示前i件物品放入容积为j的背包中的最大价值,那么对于第i件物品,它只有放与不放两种选择,那么状态转移方程就是 dp[i][j]=max{dp[i-1][j],dp[i-1][j-v[i]]+value[i]} ,,如果放的话就考虑前i-1件物品放入容积为扣掉第i件物品体积的最大价值,不放的话最大价值就是讲i-1件物品放入j体积的最大价值
实现方法是
两层循环,外层1到N表示选哪个物品,内层循环从0到V,先判断下当前的V是否放得下当前物品,然后开始状态转移。
还有一种就是只用一维数组,也就是上题的方法,f[j]表示放入容量为J的物品的最大价值,然后外层循环和第一种一样从0到N,但是内层是从V到当前体积,因为是从后往前推的,状态转移方程式
f[j]=max{f[j],f[j-volume[i]]+value[i]};