具体原理、详细描述请看初学篇
关于更多背包的内容可以在我的“背包”类别中查看
01背包
状态转移方程F[i,j]=max{F[i-1,j],F[i-1,j-wi]+vi}
CODE:
//求解将哪些物品装入背包可使这些物品的重量总和不超过背包承重量t,且价值总和最大。
#include <stdio.h>
#include <string.h>
int f[1010],w[1010],v[1010];//f记录不同承重量背包的总价值,w记录不同物品的重量,v记录不同物品的价值
int max(int x,int y){//返回x,y的最大值
if(x>y) return x;
return y;
}
int main(){
int t,m,i,j;
memset(f,0,sizeof(f)); //总价值初始化为0
scanf("%d %d",&t,&m); //输入背包承重量t、物品的数目m
for(i=1;i<=m;i++)
scanf("%d %d",&w[i],&v[i]); //输入m组物品的重量w[i]和价值v[i]
for(i=1;i<=m;i++){ //尝试放置每一个物品
for(j=t;j>=w[i];j--){//倒叙是为了保证每个物品都使用一次
f[j]=max(f[j-w[i]]+v[i],f[j]);
//在放入第i个物品前后,检验不同j承重量背包的总价值,如果放入第i个物品后比放入前的价值提高了,则修改j承重量背包的价值,否则不变
}
}
printf("%d",f[t]); //输出承重量为t的背包的总价值
printf("\n");
getch();
return 0;
}
记录路径
#include <stdio.h>
#include <string.h>
#include <iostream>
#include <algorithm>
#include <cmath>
#include <stack>
#include <queue>
#include <functional>
#include <time.h>
using namespace std;
#define inf 0x3f3f3f3f
#define PI acos(-1)
int main()
{
int m,n;
int w[110];
int v[110];
int dp[110];
int path[110][110];//标记数组
memset(path,0,sizeof(path));
scanf("%d%d",&m,&n);
for(int i=1; i<=m; i++)
scanf("%d%d",&w[i],&v[i]);
for (int i = 1; i <= m; i++)
for (int j = n; j >= w[i]; j--)
if (dp[j] < dp[j - w[i]] + v[i])
{
dp[j] = dp[j - w[i]] + v[i];
path[i][j] = 1;
}
int i = m, j = n;
while (i > 0 && j > 0)
{
if (path[i][j] == 1)
{
cout << i << ' ';
j -= w[i];
}
i--;
}
cout << endl;
cout << "总的价值为: " << dp[n] << endl;
return 0;
}
完全背包
#include<cstdio>
#include<algorithm>
using namespace std;
int w[300],c[300],f[300010];
int V,n;
int main()
{
scanf("%d%d",&V,&n);
for(int i=1; i<=n; i++)
{
scanf("%d%d",&w[i],&c[i]);
}
for(int i=1; i<=n; i++)
for(int j=w[i]; j<=V; j++)//注意此处,与0-1背包不同,这里为顺序,0-1背包为逆序
f[j]=max(f[j],f[j-w[i]]+c[i]);
printf("max=%d\n",f[V]);
return 0;
}
多重背包
#include <stdio.h>
#include <iostream>
#include <algorithm>
#include <cstring>
#define MAX 1000000
using namespace std;
int dp[MAX];//存储最后背包最大能存多少
int value[MAX],weight[MAX],number[MAX];//分别存的是物品的价值,每一个的重量以及数量
int bag;
void ZeroOnePack(int weight,int value )//01背包
{
int i;
for(i = bag; i>=weight; i--)
{
dp[i] = max(dp[i],dp[i-weight]+value);
}
}
void CompletePack(int weight,int value)//完全背包
{
int i;
for(i = weight; i<=bag; i++)
{
dp[i] = max(dp[i],dp[i-weight]+value);
}
}
void MultiplePack(int weight,int value,int number)//多重背包
{
if(bag<=number*weight)//如果总容量比这个物品的容量要小,那么这个物品可以直到取完,相当于完全背包
{
CompletePack(weight,value);
return ;
}
else//否则就将多重背包转化为01背包
{
int k = 1;
while(k<=number)
{
ZeroOnePack(k*weight,k*value);
number = number-k;
k = 2*k;//这里采用二进制思想
}
ZeroOnePack(number*weight,number*value);
}
}
int main()
{
int n;
while(~scanf("%d%d",&bag,&n))
{
int i,sum=0;
for(i = 0; i<n; i++)
{
scanf("%d",&number[i]);//输入数量
scanf("%d",&value[i]);//输入价值 此题没有物品的重量,可以理解为体积和价值相等
}
memset(dp,0,sizeof(dp));
for(i = 0; i<n; i++)
{
MultiplePack(value[i],value[i],number[i]);//调用多重背包,注意穿参的时候分别是重量,价值和数量
}
cout<<dp[bag]<<endl;
}
return 0;
}