01背包特点:
1.决策物品只有两种状态(选or不选)
2.决策物品的有权重(a[i])有上界P
3.求最大权值
4.一般物品数量较少(<100)
(注意变形)
解题:
1.手工打表:
P | P-1 | P-2 | ..... | |
1(a[1] ) | a[1] +dp[j-a[1] | a[1] | 0 | .... |
2(a[2] ) | max(a[2]+dp[j-a[2]],a[1]) | ...... | ...... | ... |
3(a[3] ) | max(a[3]+dp[j-a[3],a[2]+dp[j-a[1],a[1]+dp[j-a[1]) | ....... | ....... | .... |
dp[]值为表中所填(从左向右,从上向下)
2.写转移方程
for(int i=0;i<z;i++) //i为物品件数
{
for(int j=P;j-a[i]>=0;j--)
dp[j]=max(dp[j],dp[j-a[i]]+a[i]);
}
例题:1.Robberies
直接做有点麻烦,可以转化为在大于逃脱率的情况下可以获得的最大钱数也就是求得到某个钱数时的最大逃脱率(1-被捕率),状态转移方程是 dp[j]=max(dp[j],dp[j-s[i].m]*s[i].p)
初值dp[0]=1 ,因为不偷钱当然是不被抓的,这里的dp[j]就是获得j钱数可以达到的最大逃脱率!几次抢劫必须同时逃脱才可以,因此概率要乘!这里有个常数级的优化,可以用sum[i] 记录前i的银行(包括i)的钱数和,这样第二个循环就可以是for(j = sum[i] ; j>=s[i].m;j--) , 因为当j >sum[i] 时 j-s[i].m>sum[i-1] (sum[i]-sum[i-1]=s[i].m)这时的dp[j-s[i].m]显然还没有算出来,因为此时最多只算到了sum[i-1] !
#include<iostream>
#include<cstdio>
#include<cstring>
using namespace std;
const int N=110;
int m[N],sum[N];
double p[N],dp[N*N];
int main()
{
int t,n;
double P;
scanf("%d",&t);
while(t--)
{
memset(dp,0,sizeof(dp));
scanf("%lf%d",&P,&n);
P=1-P; //最大逃脱概率
for(int i=0;i<n;i++)
{
scanf("%d%lf",&m[i],&p[i]);
p[i]=1-p[i];
sum[i]=(i==0?m[0]:sum[i-1]+m[i]);
}
dp[0]=1;
for(int i=0;i<n;i++)
{
for(int j=sum[n-1];j>=m[i];j--)
{
dp[j]=max(dp[j],dp[j-m[i]]*p[i]);
}
}
for(int j=sum[n-1];j>=0;j--)
{
if(dp[j]>P)
{
printf("%d\n",j);
break;
}
}
}
}
整理出每张发票的总额,作为这件物品的价值也作为容量(相当于物品的体积),放到容量为q的背包中
#include<iostream>
#include<cstdio>
#include<cstring>
using namespace std;
const int N=35;
double dp[3000010];
int main()
{
char type;
int n,m,z,flag;
double q,tpa,tpb,tpc,mon,all,per[N];
while(~scanf("%lf%d",&q,&n)&&n)
{
z=0;
memset(dp,0,sizeof(dp));
for(int i=0;i<n;i++) // i zhang stamp
{
tpa=0,tpb=0,tpc=0,all=0;
flag=0;
scanf("%d",&m);
while(m--) //type
{
scanf("%*c%c:%lf",&type,&mon);
all+=mon;
if(type=='A')
tpa+=mon;
else if(type=='B')
tpb+=mon;
else if(type=='C')
tpc+=mon;
else
flag=1;
}
if(tpa<=600&&tpb<=600&&tpc<=600&&all<=1000&&!flag)
per[z++]=all*100;
}
int Q=(int)(q*100.0);
for(int i=0;i<z;i++)
{
for(int j=Q;j-(int)per[i]>=0;j--)
dp[j]=max(dp[j],dp[j-(int)per[i]]+(int)per[i]);
}
printf("%.2lf\n",dp[Q]*0.01);
}
}