动态规划法解决0-1背包问题

使用C语言实现的代码如下所示

#define _CRT_SECURE_NO_WARNINGS
#include<stdio.h>
#include<stdlib.h>

/*		   动态规划法解决0-1背包问题(使用递推公式进行数据生成)	    	*/

/* 定义背包的属性 */
int package_total_contain;		//背包的容量
int package_max_value;			//在不超过背包容量的前提下,放入背包中的物品实现的最大价值

/* 定义物品的属性 */
int goods_total_num;	  //总的物品的数量
int *pArrayGoodsWeight;	  //定义一个指针指向存放物品重量的数组
int *pArrayGoodsValue;	  //定义一个指针指向存放物品价值的数组
int *pArrayGoodsCount;	  //定义指针指向存放物品是否被选中的数组,选中就置为1,未选中就置为0,与物品一一对应,以此得出选取物品是哪些

/* 函数的声明 */
void Init();
int GetMaxValue(int goods_total_num, int package_total_contain, int *pArrayGoodsWeight, int *pArrayGoodsValue, int *pArrayGoodsCount);
void DisPlay(int maxValue);

int main() 
{
	Init();

	int maxValue = GetMaxValue(goods_total_num, package_total_contain, pArrayGoodsWeight, pArrayGoodsValue, pArrayGoodsCount);

	//maxValue的值为-1时,表示用户的输入非法,程序直接结束
	if (maxValue == -1)
	{
		system("pause");
		return 0;
	}

	DisPlay(maxValue);

	system("pause");

	return 0;

}

/* 初始化函数,进行基本数据(背包的容量、物品的数量以及各个物品的重量与价值)的初始化 */
void Init() 
{
	printf("请输入背包的的最大容量:");
	scanf("%d", &package_total_contain);

	printf("请输入物品的数量:");
	scanf("%d", &goods_total_num);

	//背包的重量有0的这一列,所以分配的空间要加1
	pArrayGoodsWeight = (int *)malloc(sizeof (int) * (goods_total_num + 1));	
	for (int i = 1; i <= goods_total_num; i++) 
	{
		printf("请输入第%d个物品的重量:",i);
		scanf("%d", pArrayGoodsWeight + i);
	}

	printf("\n");
	//物品的编号有0的这一行,所以分配的空间要加1
	pArrayGoodsValue = (int *)malloc(sizeof (int) * (goods_total_num + 1));
	for (int i = 1; i <= goods_total_num; i++) 
	{
		printf("请输入第%d个物品的价值:",i);
		scanf("%d", pArrayGoodsValue + i);
	}

	//该数组与物品编号一一对应,选中就置为1,未选中就置为0,刚开始时全部初始化为0,也是从1开始存储的
	pArrayGoodsCount = (int *)malloc(sizeof(int) * (goods_total_num + 1));
	for (int i = 1; i <= goods_total_num; i++) 
	{
		pArrayGoodsCount[i] = 0;
	}

	/* 进行用户当前基本输入数据的显示,方便用户的对比 */
	printf("\t\t\t\t您输入的数据如下图所示\n\n");

	printf("\t\t   物品序号\t\t   物品重量\t\t   物品价值\n");

	for (int i = 1; i <= goods_total_num; i++)
	{	
		printf("\t\t%8d\t\t%8d\t\t%8d\n", i, pArrayGoodsWeight[i], pArrayGoodsValue[i]);
	}
	printf("\n");
}

/*
	该函数实现生成最大价值表以及得出实现的最大价值和物品选择序列
	@param  goods_total_num			物品的总数量
	@param  package_total_contain   背包的最大容量
	@param  pArrayGoodsWeight		指向保存物品重量数组的首地址的指针变量
	@param  pArrayGoodsValue	    指向保存物品价值数组的首地址的指针变量
	@param  pArrayGoodsCount        指向保存物品是否被选中数组的首地址的指针变量
**/
int GetMaxValue(int goods_total_num, int package_total_contain, int *pArrayGoodsWeight, int *pArrayGoodsValue, int *pArrayGoodsCount) {

	//表示用户输入了背包容量或物品数量非法时,直接返回-1,将不执行生成最大价值表的程序
	if (goods_total_num <= 0 || package_total_contain <= 0)
	{
		return -1;
	}

	//表格的行数等于物品的数量,每个物品对应一行数据,由于有一行全为0,所以要加上1
	int row_num = goods_total_num + 1;

	//表格的列是按照背包重量从1开始进行递增,由于有背包重量是0的那一列,所以列数等于背包重量加1
	int col_num = package_total_contain + 1;

	//创建一个value指针变量,存放行的指针数组信息
	int ** value = (int **)malloc(sizeof (int *));

	//创建行数组,并将首地址发送给value指针
	value = (int **)malloc(sizeof(int *) * row_num);

	//创建列数组,并将首地址发送给行指针数组
	for (int i = 0; i < col_num; i++) 
	{
		value[i] = (int *)malloc(sizeof(int) * col_num);
	}

	//进行初始化操作,初始化第0行,设置该行数值为0
	for (int i = 0; i < col_num; i++)
	{
		value[0][i] = 0;
	}

	//进行初始化操作,初始化第0列,设置该行数值为0
	for (int i = 0; i < row_num; i++) 
	{
		value[i][0] = 0;
	}

	//进行计算,算出每一行每一列的最大价值,i表示物品编号,j表示背包容量
	for (int i = 1; i < row_num; i++) 
	{
		for (int j = 1; j < col_num; j++) 
		{
			//如果是该中情况,表明此时背包已经装不下了,该件物品将不会放入背包
			value[i][j] = value[i - 1][j];

			//如果物品能装入背包,此时的最大价值是该temp值
			int tempValue = value[i - 1][j - pArrayGoodsWeight[i]] + pArrayGoodsValue[i];

			//当物品能够放入背包中,并且放入的价值大于不放入的价值时,改变此时的最大价值
			if (pArrayGoodsWeight[i] <= j && tempValue > value[i][j])
			{
				value[i][j] = tempValue;
			}
		}
	}
	
	//最大价值表的列的下标最大值是col_num - 1
	int j = col_num - 1;

	/* 逆推法求出装入的物品,从最右下角开始往前推 */
	for (int i = row_num - 1; i > 0; i--) 
	{
		//如果后面的价值大于前一个,表示该物品被选进了背包
		if (value[i][j] > value[i - 1][j]) 
		{
			//设置该物品被选中,作为一种标记,设置其值为1,以便知道哪些被选中了
			pArrayGoodsCount[i] = 1;

			//将该物品的重量从总的重量中减去
			j -= pArrayGoodsWeight[i];
		}
	}

	//记录最大的价值
	int max_value = value[row_num - 1][col_num - 1];

	printf("\n");		//输出一个换行符

	printf("\t最大价值表如下图所示\n");

	printf("   ");		//输出3个空格使数据对齐

	for (int i = 0; i < col_num; i++)
	{
		printf("%3d", i);	//进行列标题的输出,表示背包的重量
	}

	printf("\n");		//输出一个换行符

	//进行当前每一个value[i][j]值的打印,行数等于物品数量加1,纵向数量等于背包最大容量加1
	for (int i = 0; i <= goods_total_num; i++)
	{
		printf("%3d", i);	

		for (int j = 0; j <= package_total_contain; j++)
		{
			printf("%3d", value[i][j]);
		}

		printf("\n");	//每输出一行进行一次换行操作
	}

	printf("\n");		//输出一个换行符


	return max_value;
}

/* 该函数实现最终结果的显示 */
void DisPlay(int maxValue) 
{
	printf("实现的最大价值是:%d\n", maxValue);

	printf("选取的物品序列是:");

	for (int i = 1; i <= goods_total_num; i++) 
	{
		if (pArrayGoodsCount[i] == 1)
		{
			printf("%d ", i);
		}
	}
	printf("\n");	
}

运行的结果如下图所示

在这里插入图片描述

  • 0
    点赞
  • 3
    收藏
    觉得还不错? 一键收藏
  • 1
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值