一、0-1背包问题的描述
下面将使用回溯法、分支界限法、动态规划法来分析和解决此问题。
二、回溯法
(1)算法步骤
(2)代码如下(没有裁剪函数):
用i和n来判断结束与否,是因为解空间结构是完全二叉树,用两节点间的边的深度表示物品序号,用两节点之间的边的01值表示该物品选择与否。
#include<stdio.h>
int n, c, bestp;//物品的个数,背包的容量,最大价值
int p[10000], w[10000], x[10000], bestx[10000];//物品的价值,物品的重量,x[i]暂存物品的选中情况,物品的选中情况
void Backtrack(int i, int cp, int cw)
{ //cw当前包内物品重量,cp当前包内物品价值
int j;
if (i>n)//回溯结束
{
if (cp>bestp)
{
bestp = cp;
for (i = 0; i <= n; i++)//这里从0开始也无妨,因为后面输出是从1开始的
bestx[i] = x[i];
}
}
else
for (j = 0; j <= 1; j++)
{
x[i] = j;
if (cw + x[i] * w[i] <= c)
{
cw += w[i] * x[i];
cp += p[i] * x[i];
Backtrack(i + 1, cp, cw);
cw -= w[i] * x[i];
cp -= p[i] * x[i];
}
}
}
int main()
{
int i;
bestp = 0;
printf("请输入背包最大容量:\n");
scanf("%d", &c);
printf("请输入物品个数:\n");
scanf("%d", &n);
printf("请依次输入物品的重量:\n");
for (i = 1; i <= n; i++)
scanf("%d", &w[i]);
printf("请依次输入物品的价值:\n");
for (i = 1; i <= n; i++)
scanf("%d", &p[i]);
Backtrack(1, 0, 0);
printf("最大价值为:\n");
printf("%d\n", bestp);
printf("被选中的物品依次是(0表示未选中,1表示选中)\n");
for (i = 1; i <= n; i++)
printf("%d ", bestx[i]);
printf("\n");
getchar(); getchar();
return 0;
}
2、动态规化
#include<stdlib.h>
#include<stdio.h>
int V[200][200];//前i个物品装入容量为j的背包中获得的最大价值
int max(int a, int b) //一个大小比较函数,用于当总重大于第I行时
{
if (a >= b)
return a;
else return b;
}
void Knap(int n, int w[], int v[], int x[], int C)
{
int i, j;
for (i = 0; i <= n; i++)
V[i][0] = 0;
for (j = 0; j <= C; j++)//j居然是离散的
V[0][j] = 0;
for (i = 0; i <= n - 1; i++)
for (j = 0; j <= C; j++)
if (j<w[i])
V[i][j] = V[i - 1][j];
else
V[i][j] = max(V[i - 1][j], V[i - 1][j - w[i]] + v[i]);
//输出相应的选择物品
j = C;
for (i = n - 1; i >= 0; i--)
{
if (V[i][j]>V[i - 1][j])
{
x[i] = 1;
j = j - w[i];
}
else
x[i] = 0;
}
printf("选中的物品是:\n");
for (i = 0; i<n; i++)
printf("%d ", x[i]);
printf("\n");
}
int main()
{
int s;//获得的最大价值
int w[4];//物品的重量 重量 价值 和物品的状态 均对应着存到数组中,物品从1开始。
int v[4];//物品的价值
int x[4];//物品的选取状态 选中则是1 没选中为0
int n, i;
int C;//背包最大容量
n = 4;
printf("请输入背包的最大容量:\n");
scanf("%d", &C);
printf("物品数:\n");
scanf("%d", &n);
printf("请分别输入物品的重量:\n");
for (i = 0; i<n; i++)
scanf("%d", &w[i]);
printf("请分别输入物品的价值:\n");
for (i = 0; i<n; i++)
scanf("%d", &v[i]);
Knap(n, w, v, x, C);
printf("最大物品价值为:\n");
printf("%d\n", s);
system("pause");
return 0;
}