这一周主要是看了一下背包问题的知识点。在学习中知道除了简单的背包外还有完全背包,多重背包还有分组的背包问题,只可惜我还没有看完。就先简单的整理几个题目吧。
如有N件物品和一个容量为V的背包。第i件物品的费用是c[i],价值是w[i]。求解将哪些物品装入背包可使价值总和最大。
基本思路:
特点:每种物品仅有一件,可以选择放或不放。
状态转移方程状态转移方程:f[i][v]=max{f[i-1][v],f[i-1][v-c[i]]+w[i]}
其中f[i][v]表示前i件物品恰放入一个容量为v的背包可以获得的最大价值。
一、简单的背包问题
如上,循环次序从大到小。
Charm Bracelet
有N件物品和一个容量为V的背包。第i件物品的费用是c,价值是w。求解将哪些物品装入背包可使这些物品的费用总和不超过背包容量,且价值总和最大。f[i][v]表示前i件物品恰放入一个容量为v的背包可以获得的最大价值。则其状态转移方程便是:f[i][v]=max{f[i-1][v],f[i-1][v-c[i]]+w[i]}
初始化细节:
若要求恰好装满背包,初始化时除了f[0]为0其它f[1…V]均设为-∞
若没有要求必须把背包装满,初始化时将f[0…V]全部设为0
代码如下:
#include<iostream>
using namespace std;
#define MAX_N 3500
#define MAX_V 20000
struct good
{
int c;
int w;
}goods[MAX_N];
int main()
{
int i,j;
int n,v;
int f[MAX_V];
while(cin>>n>>v)
{
for(i=0;i<=v;i++)f[i]=0;
for(i=0;i<n;i++)cin>>goods[i].c>>goods[i].w;
for(i=0;i<n;i++)
{
for(j=v;j>=goods[i].c;j--)
{
if(f[j]<f[j-goods[i].c]+goods[i].w)
f[j]=f[j-goods[i].c]+goods[i].w;
}
}
cout<<f[v]<<endl;
}
return 0;
}
二、完全背包
循环次序从小到大。
有N种物品和一个容量为V的背包,每种物品都有无限件可用。第i种物品的费用是c[i],价值是w[i]。求解将哪些物品装入背包可使这些物品的费用总和不超过背包容量,且价值总和最大。需要先转化为01背包,考虑到第i种物品最多选V/c[i]件,于是可以把第i种物品转化为V/c[i]件费用及价值均不变的物品,然后求解这个01背包问题 。
题目
1.有n种食物。每种食物含有的热量和带来的幸福感分别为a[i]和b[i]。一个人每天摄入的热量不超过m。求在不超过一天热量摄入量前提下,可获得的最多幸福感是多少。
#include <iostream>
#include <string.h>
#include <algorithm>
using namespace std;
int dp[100006];
int main()
{
int t,n;
while(scanf("%d",&n))
{
memset(dp,0,sizeof(dp));
int i,j,m;
int a[105],b[105];
for(i = 0; i<t; i++)
scanf("%d%d",&a[i],&b[i]);
scanf("%d",&m);
for(i = 0; i<n; i++) //状态转移方程
{
for(j = a[i]; j<=m; j++)
{
dp[j] = max(dp[j],dp[j-a[i]]+b[i]);
}
}
printf("%d\n",dp[m]);
}
return 0;
}
2、给一个储钱罐,e罐子重e,装满后重f,有n种硬币,每种重w[i],价值为p[i].问最少用多少钱可以装满罐子。如果不能装满输出This is impossible.
这个就是一个很明显的简单完全背包,只是和平时不同的是,他是求最小价值而不是最大。而且背包不是随意装而是要装满。
#include <iostream>
#include <string.h>
const int INF = 1000000000;
int f[10010];
int main()
{
int E, F, W, T, n, p, w,i , j;
scanf("%d\n",&T);
while(T--)
{
scanf("%d%d",&E,&F); W = F - E;
scanf("%d",&n);
for(i=1; i<=W; i++) f[i] = INF;
f[0] = 0;
for(i=0; i<n; i++)
{
scanf("%d%d",&p, &w);
for(j=w; j<=W; j++)
if(f[j]>f[j-w]+p)
f[j] = f[j-w]+p;
}
if(f[W]!=INF)
printf("The minimum amount of money in the piggy-bank is %d.\n",f[W]);
else
printf("This is impossible.\n");
}
return 0;
}
后面还有多重和分组的背包问题未看完,我会补充在下一周的总结中。