背包问题的C语言实现



    自打师哥布置了背包问题的作业之后,虽然看了不少次,但每次不是因为时间太紧,要不就是太难了老想逃避,一直没解决这个问题。终于借着学校运动会,抓紧时间看了看C 语言背包问题的实现,动态规划还是太难,只好先从 C 入手来解决理解一下。当时师哥提到这个背包问题的时候,我并没理解这个问题的意思,师哥给的数据是:一个容量为 10 的背包,四个物品重量分别为 5 4 6 3 ;价值为 10 40 30 5 ;求这个背包可容纳物品的最大价值?具体我当时的心理活动现在已经忘了,我只记得当时的确是理解错了,没明白什么意思。后来又去网上百度,百度的解释如下:

背包问题(Knapsack problem)是一种组合优化的NP完全问题。问题可以描述为:给定一组物品,每种物品都有自己的重量和价格,在限定的总重量内,我们如何选择,才能使得物品的总价格最高。问题的名称来源于如何选择最合适的物品放置于给定背包中。相似问题经常出现在商业、组合数学,计算复杂性理论、密码学和应用数学等领域中。也可以将背包问题描述为决定性问题,即在总重量不超过W的前提下,总价值是否能达到V?它是在1978年由MerkelHellman提出的。

背包问题已经研究了一个多世纪,早期的作品可追溯到1897 数学家托比亚斯·丹齐格(Tobias Dantzig1884-1956)的早期作品  ,并指的是包装你最有价值或有用的物品而不会超载你的行李的常见问题。

背包问题的应用:

 1998年石溪布鲁克算法库发现在75个算法问题中,背包问题是第18个最受欢迎,第4个最需要解决的问题。各种领域的决策问题都会出现,如寻找最少的浪费来削减原材料,选择投资和投资组合,选择资产支持资产证券化,和生成密钥为和其他背包密码系统。

背包问题的定义:

      我们有n种物品,物品j的重量为wj,价格为pj

我们假定所有物品的重量和价格都是非负的。背包所能承受的最大重量为W

如果限定每种物品只能选择0个或1个,则问题称为0-1背包问题

如果不限定每种物品的数量,则问题称为无界背包问题。

各类复杂的背包问题总可以变换为简单的0-1背包问题进行求解。

 

      记得刚读完百科的解释后,我想着可不可以把每个物品是否要都考虑一遍,然后全排列,看看哪种情况是正确的,后来这种做法直接被否定了,因为早考虑的情况太多,当物品非常多的时候,有可能就无法进行了。后来听同学说,考虑一件物品的去留,当时我是怀疑的,因为当从一件开始考虑时我认为这件物品和其他物品的关联就断了,也就是说你不能考虑整体的,可当真正开始处理的时候才明白,从一个物品开始,一个个考虑,是背包问题C语言解决的思路。

#include"stdio.h"
#define MAX 20
 
int Min(int x, int y)
{
return x <= y ? x : y;
}
 
int Max(int x, int y)
{
return x >= y ? x : y;
}
 
void TraceBack(int (*middle)[MAX], int *weight, int column, int length, int *x)
{
int i;
for(i = 1; i < length; i++)
if(middle[i][column] == middle[i + 1][column])
x[i] = 0;
else
{
x[i] = 1;
column -= weight[i];
}
x[length] = (middle[length][column] ? 1 : 0);
}
 
void Knapsack(int *value, int *weight, int column, int length, int (*middle)[MAX])
{
int i, j, jMax = Min(weight[length] - 1, column);
for(j = 0; j <= jMax; j++)//从最后一个开始观察,因为最后一个代码没有前面值,所以需要单独写
 
middle[length][j] = 0;
for(j = weight[length]; j <= column; j++)
middle[length][j] = value[length];
for(i = length - 1; i > 1; i--)//中间的代码一个一个单独敲
{
jMax = Min(weight[i] - 1, column);
for(j = 0; j <= jMax; j++)
middle[i][j] = middle[i + 1][j];
for(j = weight[i]; j <= column; j++)
middle[i][j] = Max(middle[i + 1][j], middle[i + 1][j - weight[i]] + value[i]);
}
middle[1][column] = middle[2][column];//最后的一组可以不考虑前面的情况,直接考虑最后他自己是否需要加入就可以
if(column >= weight[1])
middle[1][column] = Max(middle[1][column], middle[2][column - weight[1]] + value[1]);
}
 
int main(void)
{
int i, length, column, count = 0, wj[MAX], pj[MAX], x[MAX] = {0}, middle[MAX][MAX] = {0};
printf("请输入背包总容量:\n");
scanf("%d", &column);
printf("请输入物品个数:\n");
scanf("%d", &length);
/*if(length < 1)
{
printf("输入错误!!!\n");
return;
}//判断*/
for(i = 1; i <= length; i++)
{
printf("请输入第%d个物品的重量及价值:\n", i);
scanf("%d %d", wj + i, pj + i);//为什么不在0开始
}
Knapsack(value, wj, column, length, middle);
TraceBack(middle, wj, column, length, x);
printf("Result:\n");
for(i = 1; i <= length; i++)
if(x[i])
printf("Number: %d, ", i);
printf("\n");
}


                
  • 5
    点赞
  • 35
    收藏
    觉得还不错? 一键收藏
  • 3
    评论
评论 3
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值