动态规划 01背包问题
动态规划处理当前项时,只有两种选择:选 / 不选。
那么问题简化为:什么情况选,什么情况不选(出口)
问题描述:
现在有4个物品,背包总容量为8,物品如何装入背包总价最大
01背包问题:每种物品只能装一次
出口有 3 种:
i
f
:
背
包
剩
余
可
装
重
量
为
0
:
不
能
装
任
何
一
个
物
品
,
此
时
总
价
v
a
l
u
e
=
0
(
第
一
列
初
始
值
)
if :背包剩余可装重量为 0:不能装任何一个物品,此时总价 value = 0(第一列初始值)
if:背包剩余可装重量为0:不能装任何一个物品,此时总价value=0(第一列初始值)
i
f
:
没
有
物
品
:
背
包
也
选
不
了
物
品
,
此
时
总
价
v
a
l
u
e
=
0
(
第
一
行
初
始
值
)
if : 没有物品:背包也选不了物品,此时总价 value = 0(第一行初始值)
if:没有物品:背包也选不了物品,此时总价value=0(第一行初始值)
i
f
:
物
品
重
量
大
于
背
包
剩
余
重
量
,
只
能
不
选
if :物品重量大于背包剩余重量,只能不选
if:物品重量大于背包剩余重量,只能不选
1
2
3
4物品编号 1 2 3 4 物品体积 2 3 4 5 物品价值 3 4 5 6
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86# include <stdio.h> # include <stdlib.h> int weight[5] = {0, 2, 3, 4, 5}; // 0 :背包容量已用完 int value[5] = {0, 3, 4, 5, 6}; // 0 :不选 int dp[5][9] = {0}; // 放总价的矩阵 初始化全0矩阵 (背包容量为8: 0~8 共9列) int object[5]; void dpMax(); // 动态规划找能装下且价值最高解 void find(int i, int j); // 回溯找回装了哪些物品 int max(int a, int b); // 找最大值函数 void outDP(); int main() { dpMax(); printf("--------n"); outDP(); printf("--------n"); find(4, 8); // dp矩阵从[0][0]到[4][8] 即返回矩阵右下角格子 return 0; } void dpMax() { // 从矩阵左上角向右下角计算,每次计算都会用到已有结果的上一排/上一列的值 // 但矩阵第一行/第一列是出口,已经有值(为0)。即依旧从后往前选 for (int i = 1; i < 5; i++) { for (int j = 1; j < 9; j++) { if (weight[i] > j) { // 物品重量比背包剩下重量大,不选 dp[i][j] = dp[i - 1][j]; printf("dp[%d][%d] = %d ", i, j, dp[i][j]); } else { int A = value[i] + dp[i - 1][j - weight[i]]; // 选 int B = dp[i - 1][j]; // 不选 dp[i][j] = max(A, B); // 选与不选中总价大的 printf("dp[%d][%d] = %d ", i, j, dp[i][j]); } } printf("n"); } } int max(int a, int b) { return a > b ? a : b; } // 递归写法 // 回溯 从矩阵最右下角往左上角推 void find(int i, int j) { printf("定位到 dp[%d][%d]n", i, j); if (i == 0) { // 先写递归出口,已经从右下角找到左上角 for (int k = 0; k < 5; k++) { printf("%d ", object[k]); } return ; } if (dp[i][j] == dp[i - 1][j]) { // 没装 object[i] = 0; find(i - 1, j); // 往上移一个 } else if (dp[i][j] == dp[i - 1][j - weight[i]] + value[i] ) { // 装了 object[i] = 1; find(i - 1, j - weight[i]); } } // 打印dp void outDP() { for (int i = 0; i < 5; i++) { for (int j = 0; j < 9; j++) { printf("dp[%d][%d] = %d ", i, j, dp[i][j]); } printf("n"); } }
输出:
回溯
dp[ i ] [ j ] 与 dp[ i -1] [ j ] 上下不一样说明,第 i 个物品装入了背包
最后
以上就是专注蜡烛最近收集整理的关于动态规划 / 回溯算法【01背包问题】 (C语言)动态规划 01背包问题问题描述:回溯的全部内容,更多相关动态规划内容请搜索靠谱客的其他文章。
发表评论 取消回复