目录
好了,终于静下心来搞背包了。有点不应该,回避了这么久。
【01背包】
- 给你n种不同的物品,每个物品有自己的体积w[i]和价值v[i],如果每个物品只能拿一次,给你容量为m的背包,怎样才能获取最大价值;
- 主线:使容量为m的背包装入的物品价值最大;
- 状态转移方程:dp[j]=max{ dp[j], dp[j-w[i]] +v[i]] };
- dp[j] 记录当容量为j时的可行取法的最大价值
- 核心代码:
for(i=0;i<n;i++)
for(j=m;j>=w[i];j--)//每种物品,要么取要么不取
dp[j] = max( dp[j], dp[j-w[i]]+v[i] )
例题:
【hdu 2602】Bone Collector(裸题)
#include<bits/stdc++.h>
using namespace std;
const int maxn=1e3+5;
int w[maxn],v[maxn],dp[maxn];
int main()
{
int t;
scanf("%d",&t);
while(t--)
{
int n,m;
scanf("%d%d",&n,&m);
for(int i=0;i<n;i++)
scanf("%d",&v[i]);
for(int i=0;i<n;i++)
scanf("%d",&w[i]);
memset(dp,0,sizeof(dp));
for(int i=0;i<n;i++)
{
for(int j=m;j>=w[i];j--)
dp[j]=max(dp[j],dp[j-w[i]]+v[i]);
}
printf("%d\n",dp[m]);
}
}
【hdu2546】饭卡
如果饭卡里的钱以及小于5元,直接输出了;否则,先把菜价格升序排列,用5元去买最贵的菜,再将剩下的菜和钱做01背包处理。此时,总容量就相当于是m-5。
#include<bits/stdc++.h>
using namespace std;
const int maxn=1e3+5;
int a[maxn],dp[maxn];
int main()
{
int n;
while(~scanf("%d",&n)&&n)
{
for(int i=0;i<n;i++)
scanf("%d",&a[i]);
int m;
scanf("%d",&m);
if(m<5){
printf("%d\n",m);
continue;
}
sort(a,a+n);
memset(dp,0,sizeof(dp));
for(int i=0;i<n-1;i++)
for(int j=m-5;j>=a[i];j--)
dp[j]=max(dp[j],dp[j-a[i]]+a[i]);
printf("%d\n",m-dp[m-5]-a[n-1]);
}
return 0;
}
【hdu2955】Robberies(二重背包)
从反面入手,只要不被抓的概率小于1-p就好。
// 嗯....这里不太懂为什么dp[0]要赋值为1;
#include<bits/stdc++.h>
using namespace std;
#define eps 0.00000000001
struct node{
int val;
double w;
}a[5007];
double dp[5007];
int main()
{
int t;
scanf("%d",&t);
while(t--)
{
memset(dp,0,sizeof(dp));
dp[0]=1;//??????????
int n,sum=0;
double v;
scanf("%lf%d",&v,&n);
v=1-v;
for(int i=0;i<n;i++)
{
scanf("%d%lf",&a[i].val,&a[i].w);
a[i].w=1-a[i].w;
sum+=a[i].val;
}
for(int i=0;i<n;i++)
for(int j=sum;j>=a[i].val;j--)
dp[j]=max(dp[j],dp[j-a[i].val]*a[i].w);
for(int i=sum;i>=0;i--)
if(v-dp[i]<eps)
{
printf("%d\n",i);
break;
}
}
return 0;
}