动态规划之0-1背包问题
动态规则:把多阶段过程转化为一系列单阶段问题,利用各阶段之间的关系,逐个求解,创立了解决这类过程优化问题的方法。
题目描述:
有编号分别为a,b,c,d,e的五件物品(各只有一件),它们的重量分别是4,5,6,2,2,它们的价值分别是6,4,5,3,6,现在给你个承重为10的背包,如何让背包里装入的物品具有最大的价值总和?
0-1背包问题,是用来介绍动态规划算法最经典的例子。
0-1背包的状态转换方程:f[i, j] = Max{ f[i - 1, j - Wi] + Vi, f[i - 1, j] },(j >= Wi)
- f[i,j]:表示在前i件物品中选择若干件放在承重为j的背包中,可以取得的最大价值。
- Wi:是第i种物品的重量;
- Vi:表示第i件物品的价值。
决策:为了背包中物品总价值最大化,第i件物品应该放入背包中吗?
name | weight | value | 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 |
a | 4 | 6 | 0 | 0 | 0 | 6 | 6 | 6 | 6 | 6 | 6 | 6 |
b | 5 | 4 | 0 | 0 | 0 | 6 | 6 | 6 | 6 | 6 | 10 | 10 |
c | 6 | 5 | 0 | 0 | 0 | 6 | 6 | 6 | 6 | 6 | 10 | 11 |
d | 2 | 3 | 0 | 3 | 3 | 6 | 6 | 9 | 9 | 9 | 10 | 11 |
e | 2 | 6 | 0 | 6 | 6 | 9 | 9 | 12 | 12 | 15 | 15 | 15 |
根据上面的公式可以很容易的得出这张表,最右下边的值15即为解。
代码实现:
#include <stdio.h>
int dp[2014][1024];
char item[] = { 'a', 'b', 'c', 'd', 'e' };
int max(int x, int y)
{
return x > y ? x : y;
}
void packgeProblem(int sumW, int n, int *w, int *v, int *x)
{
for (int i = 0; i <= n; i++)
dp[i][0] = 0; // 首行清0
for (int j = 0; j <= sumW; j++)
dp[0][j] = 0; // 首列清0(其实这步没有必要)
for (int i = 1; i <= n; i++)
{
for (int j = 1; j <= sumW; j++)
{
if (j >= w[i - 1])
dp[i][j] = max(dp[i - 1][j], v[i-1] + dp[i - 1][j-w[i - 1]]); // 取(上格)与(些物品价值+剩余重量所能装的上行价值)最大值
else
dp[i][j] = dp[i - 1][j]; // 如果背包剩余重量不足,取上行值
}
}
for (int i = n,j=sumW; i > 0; i--) // 标识所选物品
{
if (dp[i][j] > dp[i - 1][j])
{
x[i - 1] = 1; // 已选
j -= w[i - 1];
}
else x[i - 1] = 0; // 未选
}
for (int i = 0; i < n; i++)
if (x[i] == 1) printf("%c ", item[i]);
printf("\n");
}
int main()
{
int w[6] = {4, 5, 6, 2, 2 };
int v[6] = {6, 4, 5, 3, 6 };
int sumW = 10;
int x[6] = { 0, 0, 0, 0, 0 };
packgeProblem(sumW, 5, w, v, x);
getchar();
return 0;
}