思路:
动态规划:
假设可选物品集合为S, Sk为前k个物品组成的物品子集, 第k个物品的体积是wk,价值是vk
1. 表征子问题:用B[k,w] 表示在子集Sk中,所剩空间为w时,能够装下的物品最大价值。
2. 状态迁移方程:则从含有n个物品的集合中,用W大小的背包,能装下物品的最大价值是B[n, W],由子问题表示可知:
B[k, w] = B[k-1, w] wk > w
= max(B[k-1, w], B[k, w - wk] + vk) wk <= w
动态规划:
假设可选物品集合为S, Sk为前k个物品组成的物品子集, 第k个物品的体积是wk,价值是vk
1. 表征子问题:用B[k,w] 表示在子集Sk中,所剩空间为w时,能够装下的物品最大价值。
2. 状态迁移方程:则从含有n个物品的集合中,用W大小的背包,能装下物品的最大价值是B[n, W],由子问题表示可知:
B[k, w] = B[k-1, w] wk > w
= max(B[k-1, w], B[k, w - wk] + vk) wk <= w
当当前物体的体积wk大于当前背包的剩余空间的时候,不选择放入物品。当当前还有空间可以放下,则是否选择放入物品,取决于放入之后可获得的价值是否大于不放入可获得的最大价值。
int B[35][20005];
int knapsack(int *W, int n, int V)
{
for(int k = 1; k <= n; k++){
for(int w = 0; w <= V; w++){
if(w < W[k]){
B[k][w] = B[k-1][w];
}else{
B[k][w] = max(B[k - 1][w], B[k - 1][w - W[k]] + W[k]);
}
}
}
return B[n][V];
}
算法分析:
给定整数W和n个物品的集合S,每个物品有正整数型的权值,可以用O(nW)时间求出S中的总权值之多为W且具有最大效用的子集。
伪多项式时间算法:
算法的运行时间依赖于W(背包的大小),如果W很大(2^n)那么这个动态规划算法渐进的比蛮力方法要慢。
一般称像背包动态规划这样的算法为伪多项式时间算法,因为它的运行时间依赖于输入中给定的某个数的量。
改进:
依据上面的分析,可以用一个一维数组来做:
子问题:用B[w]表示在背包剩余空间为w的情况下,从Sk子集中能够选出的最大价值。
状态迁移方程:B[w] = max(B[w], B[w-wk] + vk)
int B[BUF_SIZE];
int knapsack(int *W, int n, int V)
{
for (int k = 1; k <= n; k++) {
for (int w = V; w >= W[k]; w--) {
B[w] = max(B[w], B[w - W[k]] + W[k]);
}
}
return B[V];
}