在M件物品取出若干件放在空间为W的背包里,每件物品的体积为W1,W2……Wn,与之相对应的价值为P1,P2……Pn。求出获得最大价值的方案。
注意:在本题中,所有的体积值均为整数。01的意思是,每个物品都是一个整体,要么整个都要,要么都不要。
1)最优子结构
考虑所有物品的子集合,考虑第n个物品都有两种情况: 1. 包括在最优方案中 2. 不在最优方案中
因此,能获得的最大价值,即为以下两个值中较大的那个
1) 在剩下 n-1 个物品中(剩余 W 重量可用)的情况能得到的最大价值 (即排除了 第n个物品)
2) 第n个物品的价值 加上 剩下 剩下的 n-1 个物品(剩余W- wn的重量)能得到的最大价值。(即包含了第n个物品)
如果第n个物品的重量,超过了当前的剩余重量W,那么只能选情况1), 排除第n个物品。
2) 重叠子问题
下面是一个递归的实现,按照上面的最优子结构。
01 |
/* 朴素的递归实现 0-1 背包 */ |
02 |
#include<stdio.h> |
03 |
04 |
int max( int a, int b) { return (a > b)? a : b; }
|
05 |
06 |
// 返回 前n个物品在容量为W时,能得到的最大价值 |
07 |
int knapSack( int W, int wt[], int val[], int n)
|
08 |
{ |
09 |
// 没有物品了
|
10 |
if (n == 0 || W == 0)
|
11 |
return 0;
|
12 |
13 |
// 如果当前第n个物品超重了,就排除在外
|
14 |
if (wt[n-1] > W)
|
15 |
return knapSack(W, wt, val, n-1);
|
16 |
17 |
//返回两种情况下最大的那个 (1) 包括第n个物品 (2) 不包括第n个物品
|
18 |
else return max( val[n-1] + knapSack(W-wt[n-1], wt, val, n-1),
|
19 |
knapSack(W, wt, val, n-1)
|
20 |
);
|
21 |
} |
22 |
23 |
// 测试 |
24 |
int main()
|
25 |
{ |
26 |
int val[] = {60, 100, 120};
|
27 |
int wt[] = {10, 20, 30};
|
28 |
int W = 50;
|
29 |
int n = sizeof (val)/ sizeof (val[0]);
|
30 |
printf ( "%d" , knapSack(W, wt, val, n));
|
31 |
return 0;
|
32 |
} |
这种方法其实就是搜索了所有的情况,但是有很多重复的计算。时间复杂度是指数级的 O(2^n)。
01 |
在下面的递归树中 K() 代表 knapSack(). |
02 |
输入数据如下: |
03 |
wt[] = {1, 1, 1}, W = 2, val[] = {10, 20, 30} |
04 |
05 |
K(3, 2) ---------> K(n, W)
|
06 |
/ \
|
07 |
/ \
|
08 |
K(2,2) K(2,1)
|
09 |
/ \ / \
|
10 |
/ \ / \
|
11 |
K(1,2) K(1,1) K(1,1) K(1,0)
|
12 |
/ \ / \ / \
|
13 |
/ \ / \ / \
|
14 |
K(0,2) K(0,1) K(0,1) K(0,0) K(0,1) K(0,0) |
可见相同的子问题被计算多次。01背包满足动态规划算法的两个基本属性(重叠子问题和最优子结构)。可以通过自下而上的打表,存储中间结果,来避免重复计算。动态规划解法如下:
01 |
#include<stdio.h> |
02 |
int max( int a, int b) { return (a > b)? a : b; }
|
03 |
04 |
int knapSack( int W, int wt[], int val[], int n)
|
05 |
{ |
06 |
int i, w;
|
07 |
int dp[n+1][W+1];
|
08 |
09 |
for (i = 0; i <= n; i++)
|
10 |
{
|
11 |
for (w = 0; w <= W; w++)
|
12 |
{
|
13 |
if (i==0 || w==0)
|
14 |
dp[i][w] = 0;
|
15 |
else if (wt[i-1] <= w)
|
16 |
dp[i][w] = max(val[i-1] + dp[i-1][w-wt[i-1]], dp[i-1][w]);
|
17 |
else
|
18 |
dp[i][w] = dp[i-1][w];
|
19 |
}
|
20 |
}
|
21 |
return dp[n][W];
|
22 |
} |
23 |
24 |
int main()
|
25 |
{ |
26 |
int val[] = {60, 100, 120};
|
27 |
int wt[] = {10, 20, 30};
|
28 |
int W = 50;
|
29 |
int n = sizeof (val)/ sizeof (val[0]);
|
30 |
printf ( "%d" , knapSack(W, wt, val, n));
|
31 |
return 0;
|
32 |
} |
空间复杂度和时间复杂度都为 O(Wn). 由于打表的过程中,计算的当前行只依赖上一行,空间复杂度可以优化为O(W);
参考:http://www.geeksforgeeks.org/dynamic-programming-set-10-0-1-knapsack-problem/
更多关于算法分析的文章:http://www.acmerblog.com/category/zhuanti/algorithm
相关推荐
本篇文章将深入探讨C#语言实现动态规划解决01背包问题的详细过程。 01背包问题是一个经典的组合优化问题,常见于计算机科学和运筹学。问题设定如下:假设我们有一组物品,每个物品都有一个重量和一个价值,我们需要...
动态规划求解0-1背包问题的改进算法完整解释 在计算机算法设计与分析中,动态规划法是解决背包问题的常用方法之一。所谓背包问题,是指在有限的背包容量下,如何选择物品来达到最大价值的问题。在本文中,我们将对...
01背包问题,桂林电子科技大学算法设计实验报告
利用动态规划方法求解经典0-1背包问题,仅供参考,欢迎指正
对于0-1背包问题,动态规划的解决方案通常包括以下步骤: 1. 初始化:创建一个二维数组`dp`,其中`dp[i][j]`表示在前`i`件物品中选择总重量不超过`j`的物品所能得到的最大价值。初始化时,`dp[0][j] = 0`,因为没有...
利用动态规划解决01背包问题 动态规划是一种非常重要的算法方法,它可以用来解决许多复杂的问题,例如经济管理、生产调度、工程技术和最优控制等方面的问题。01背包问题是动态规划的经典模型之一,它可以用于解决...
提供0-1背包问题c++代码,实现功能如下: /**输入参数: * @param m 表示背包的最大容量 * @param n 表示商品个数 * @param a[] 每个商品的容量 * @param p[] 每个商品的价值 */ /**输出: 求最大商品value*/
01背包问题是一种经典的动态规划问题,主要应用于优化资源分配以获取最大效益。在这个问题中,我们有N种物品,每种物品有一个固定的体积wi和对应的价值ci,还有一个总容量为V的背包。目标是在不超过背包容量的情况下...
总之,0-1背包问题是一种重要的算法问题,通过学习和理解其动态规划解决方案,我们可以提升解决问题的能力,并将其应用到实际问题中,如资源分配、任务调度等领域。对于编程爱好者和IT专业人士来说,掌握这类问题的...
0-1背包问题是一种经典的动态规划问题,在计算机科学与信息技术领域,特别是在算法设计与分析中占有重要地位。这个问题源于实际生活中的物品打包问题,比如在有限的背包容量下,如何选择物品以使得总价值最大。这里...
动态规划解决01背包问题 动态规划是解决01背包问题的有效方法,该方法的核心是填表,通过填表来找到问题的最优解。下面对动态规划解决01背包问题的知识点进行详细的解释。 一、问题描述 01背包问题是指有n个物品...
解决0-1背包问题常用的方法是动态规划。动态规划的核心思想是通过构建子问题的解决方案来解决原问题。具体到0-1背包问题,我们可以定义状态dp[i][j]表示前i个物品放入容量为j的背包中所能获得的最大价值。 #### 三...
动态规划法解决0-1背包问题,非常实用,课程实验经常用到
动态规划法解0-1背包问题是一种常见的优化问题,在计算机科学和算法设计中占有重要地位。0-1背包问题的基本设定是:有一组物品,每种物品都有一个重量和一个价值,目标是在不超过背包总承重的情况下,选择物品使得...
0-1背包问题是一个经典的组合优化...回溯法和分支限界法则适用于更广泛的搜索问题,但在0-1背包问题中,它们通常不如动态规划法效率高。在实际应用中,选择哪种算法取决于问题的具体特性以及对时间和空间复杂度的要求。
0-1背包问题的动态规划表格通常是一个二维数组,其中行代表物品,列代表背包的容量。每个单元格的值表示在当前容量下,考虑前n个物品能获得的最大价值。 二、分支限界法(Branch and Bound) 分支限界法是一种全局...
0-1背包问题是一种经典的组合优化问题,在计算机科学和运筹学中有着广泛的应用。它描述的是这样的场景:你有一组物品,...在阅读“算法实验报告之01背包-----张宇.doc”时,可以更深入地理解这些问题的细节和优化策略。
01背包问题动态规划