您的位置:首页 > 其它

动态规划之0-1背包问题

2013-08-28 10:52 316 查看

本博客已迁往http://coredumper.cn

0-1背包问题的解决思路如下:

假设可选物品的个数为SIZE,用0~SIZE-1分别表示每个物品的索引号,数组w[SIZE]表示每个物品的重量,数组v[SIZE]表示每个物品的价值,f(i, aw)表示当可选取的物品索引号在0~i之间,并且背包还可以容纳的重量为aw时的最大价值。

则有如下4中情况:

当i=0且w[i]>aw时,f(i, aw)=0

当i=0且w[i]<=aw时,f(i, aw)=v[i]

当i>0且w[i]>aw时,f(i, aw)=f(i-1, aw)

当i>0且w[i]<=aw时,f(i, aw)=max( f(i-1, aw),  v[i]+f(i-1, aw-w[i]) )

下面分别给出原始递归算法和动态规划的备忘录方法的源码。

原始递归算法,该算法需要大量重复计算相同子问题:

#include <stdio.h>
#define SIZE 10 //可选的物品数量
#define AW 20   //背包可以装下的最大重量

/* 参数w代表每种物品的重量,参数v代表每种物品的价值,
参数index代表物品的索引号,参数aw代表背包还可以容纳的重量*/
int knapSack(int w[], int v[], int index, int aw)
{
if(index == 0){
if(w[index] <= aw){
return v[index];
}
return 0;
}
int withoutIndex, withIndex;
withoutIndex = knapSack(w, v, index - 1, aw);
if(w[index] > aw){
return withoutIndex;
}
withIndex = v[index] + knapSack(w, v, index - 1, aw - w[index]);
if(withoutIndex > withIndex){
return withoutIndex;
}
return withIndex;
}

int main()
{
int w[SIZE] = {5, 3, 2, 7, 8, 9, 10, 5, 3, 2};
int v[SIZE] = {9, 7, 8, 10, 11, 15, 20, 8, 6, 7};
printf("%d\n", knapSack(w, v, SIZE - 1, AW));
return 0;
}

动态规划的备忘录方法:

/* 用二维数组m[i][j]存放当可选取的物品索引号在0~i之间,
并且背包还可以容纳的重量为j时的最大价值,可避免重复解决相同子问题。
*/
#include <stdio.h>
#define SIZE 10
#define AW 20

int knapSack(int w[], int v[], int index, int aw, int m[][AW+1])
{
if(m[index][aw] != -1){
return m[index][aw];
}

if(index == 0){
if(w[index] <= aw){
m[index][aw] = v[index];
return v[index];
}
m[index][aw] = 0;
return 0;
}
int withoutIndex, withIndex;
withoutIndex = knapSack(w, v, index - 1, aw, m);
if(w[index] > aw){
m[index][aw] = withoutIndex;
return withoutIndex;
}
withIndex = v[index] + knapSack(w, v, index - 1, aw - w[index], m);
if(withoutIndex > withIndex){
m[index][aw] = withoutIndex;
return withoutIndex;
}
m[index][aw] = withIndex;
return withIndex;
}

int memKS(int w[], int v[], int index, int aw)
{
int m[SIZE][AW+1];
int i, j;
for(i = 0; i < SIZE; ++i){
for(j = 0; j <= AW; ++j){
m[i][j] = -1;
}
}
return knapSack(w, v, index, aw, m);
}

int main()
{
int w[SIZE] = {5, 3, 2, 7, 8, 9, 10, 5, 3, 2};
int v[SIZE] = {9, 7, 8, 10, 11, 15, 20, 8, 6, 7};
printf("%d\n", memKS(w, v, SIZE - 1, AW));
return 0;
}


备忘:以上给出的两种解法均只能计算出最大价值,但是没有给出应该取出物品的索引号;另外还缺少动态规划的迭代方法。
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息