问题
知道每个物体重量和价值,给你一个背包,计算所能装走物体的最大价值。
例如:
背包容量:8kg;
物体重量
编号 | 重量/kg | 价值 |
---|---|---|
0 | 2 | 3 |
1 | 3 | 4 |
2 | 4 | 5 |
3 | 5 | 6 |
为什么叫01背包问题
答:因为每个物体都只有两种选择,装或者不装,称这种每个物体只有两种选择的问题称为01背包问题。
解题思路
-
每个物体只有两种选择,即装与不装
-
背包的最大价值为某个物体装和不装的这两种情况下的价值最大值。
装:
总价值增加v,背包容量减少w;(假设该物体重w,价值v);
总价值为 v + 其他物体(背包容量减小后所能装下)的总价值,需要计算背包容量减小后所能装下的其他物体的总价值。
不装:
总价值为其他所有物体(背包所能装下)的最大价值。
以上产生了两个子问题。 -
按顺序决策每个物体到底装与不装。
状态转移方程
ValueArray[objPacked][packCap] = max(
/该物体装/ ValueArray[objPacked - 1][packCap - w[objPacked]] + v[objPacked],
/不装/ValueArray[objPacked - 1][packCap]
)
objPacked: 当前决策的物体的索引号,也表示前几个物体,决策的顺序是从索引号0开始依次增加的。
packCap:背包的剩余容量。每个物体决策后背包容量会有变化。
ValueArray:表示背包容量packCap下,前几个物体中所能装得下的最大价值。
重点:生成一个这样的状态方程表。
状态表
特殊情况:
背包容量装不下当前物体时,最大价值等于前几个物体的最大价值。
packCap < w[i] : ValueArray[objPacked][packCap - 1]
packCap >= w[i] : max(
ValueArray[objPacked - 1][packCap - w[objPacked]] + v[objPacked],
ValueArray[objPacked - 1][packCap]
)
计算状态表:
遍历物体索引号和背包容量,计算背包容量在0,1…packCap下,所能装的前几个物体的最大价值。(空间时间复杂读都为O(n2),还有没有其他好方法?todo)
源码(C)
#include <stdio.h>
typedef struct {
unsigned int weight;
unsigned int value;
}OBJ_T;
#define MAX_OBJ_CNT 4
#define MAX_PACKAGE_CAP 8
#define MAX(a, b) ((a) > (b) ? (a) : (b))
int pockage01(OBJ_T* objList, int objNum, int packCap);
int main()
{
/**/
int maxValue = 0;
int i = 0;
OBJ_T objList[MAX_OBJ_CNT];
objList[0].weight = 2;
objList[0].value = 3;
objList[1].weight = 3;
objList[1].value = 4;
objList[2].weight = 4;
objList[2].value = 5;
objList[3].weight = 5;
objList[3].value = 6;
for (i = 0; i < MAX_OBJ_CNT; i++)
{
printf("weight:%d, value:%d\n", objList[i].weight, objList[i].value);
}
maxValue = pockage01(objList, MAX_OBJ_CNT, MAX_PACKAGE_CAP);
printf("maxvalue:%d\n", maxValue);
return 0;
}
/*return max value*/
int pockage01(OBJ_T* objList, int objNum, int packCap)
{
if (objNum > MAX_OBJ_CNT || packCap > MAX_PACKAGE_CAP || objList == NULL)
{
return 0;
}
/**/
int valueArray[MAX_OBJ_CNT][MAX_PACKAGE_CAP+1] = {0};
int objPacked = 0;
int PackRemain = 0;
for (PackRemain = 1; PackRemain <= packCap; PackRemain++)
{
printf("\t[%d]", PackRemain);
}
for (objPacked = 0; objPacked < objNum; objPacked++)
{
printf("\n[%d]:\t", objPacked);
for (PackRemain = 1; PackRemain <= packCap; PackRemain++)
{
if (objPacked == 0)
{
if (PackRemain >= objList[objPacked].weight)
{
valueArray[objPacked][PackRemain] = objList[objPacked].value;
}
}
else
{
if (PackRemain >= objList[objPacked].weight)
{
valueArray[objPacked][PackRemain] = MAX(valueArray[objPacked - 1][PackRemain],
valueArray[objPacked - 1][PackRemain - objList[objPacked].weight] + objList[objPacked].value);
}
else
{
valueArray[objPacked][PackRemain] = valueArray[objPacked - 1][PackRemain];
}
}
printf("%d\t", valueArray[objPacked][PackRemain]);
}
printf("\n");
}
return valueArray[objNum-1][packCap];
}
输出: