// 背包问题:
// 现有四个物品,背包总量为8,背包最多能装入价值为多少的物品?
// i 物品编号:1 2 3 4
// w 体积 :2 3 4 5
// v 价值 :3 4 5 6
#include<stdio.h>
#include<math.h>
int volume[5] = { 0,2,3,4,5 }; // 物品体积
int value[5] = { 0,3,4,5,6 }; // 物品价值
int dp[5][9] = { 0 }; // 动态规划矩阵横坐标为背包容量,纵坐标为物品编号
int object[5] = { 0 }; // 若i物品有装入背包,则object[i]修改为1
// 返回两个值中的的最大值
int max(int a, int b)
{
if (a > b)
return a;
return b;
}
// 动态规划找到背包所能装下的最大价值
void Dynamic()
{
// 由物品1至4,背包容量由0至8依次考虑
for (int i = 1; i < 5; i++)
{
for (int j = 1; j < 9; j++)
{
if (volume[i] > j)
{
// 若容量为j的背包本身就装不下第i个物品,则不考虑装入物品i的情况
// 因此考虑i物品与不考虑i物品的最优值相同
dp[i][j] = dp[i - 1][j];
}
else
{
// 若容量为j的背包可以装下第i个物品
// 则比较i物品不装入背包dp[i - 1][j],与i物品装入背包dp[i - 1][j - volume[i]] + value[i]两种情况
// 应注意的是,将i物品装入背包时,需预留出i物品的体积volume[i],再考虑体积为j - volume[i],
// 考虑前i - 1个物品的情况下的最优值,最后再加上i的价值
dp[i][j] = max(dp[i - 1][j], dp[i - 1][j - volume[i]] + value[i]);
}
}
}
}
// 回溯找回装了哪些物品
// 从dp[4][8]开始回溯
void Find(int i, int j)
{
if (i == 0)
return;
if (dp[i][j] == dp[i - 1][j]) // 这说明物品i没有被装入背包
{
object[i] = 0;
Find(i - 1, j); // 递归寻找背包剩余容量为j时,物品i - 1是否被装入背包
}
else if (dp[i][j] == dp[i - 1][j - volume[i]] + value[i]) // 这说明物品i有被装入背包
{
object[i] = 1;
Find(i - 1, j - volume[i]); // 递归寻找在背包剩余容量为j - volume[i]时,
// 物品i - 1是否被装入背包
}
}
int main()
{
Dynamic();
// 从dp[4][8]开始回溯
Find(4, 8);
// 打印dp矩阵,横坐标为背包容量,纵坐标为物品编号
printf("dp矩阵如下:\n");
for (int i = 0; i < 5; i++)
{
for (int j = 0; j < 9; j++)
{
printf("%d ", dp[i][j]);
}
printf("\n");
}
printf("\n");
// 打印object矩阵
printf("object矩阵如下:\n");
for (int i = 1; i < 5; i++)
{
printf("%d ", object[i]);
}
return 0;
}
输出结果如下: