数据结构之非递归解决0-1背包问题

很早前就想写博客记录下自己的学习路程,

就从今天开始写起把。那啥今天周末,大家好多人应该都出去玩了。

当然在寝室dota的也有拉,哈哈。

希望那些以爱好programming的大哥大姐大叔大婶小弟小妹都能坚持下来。

前面的路还很长,要学的也很多。专注你所学的,多思考,多动手,多调试。就一定会有收获。

该程序在gcc和vc下通过。

 转载请注明出处,谢谢!

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

//先排序
//很简单的一种排序,不要bs俺
void sort(int *p, int num)
{
	for (int i = 0; i < num - 1; i++){
		for (int j = i + 1; j < num; j++){
			if (p[i] > p [j]){//利用加法交换
				p[i] += p[j];
				p[j] = p[i] - p[j];
				p[i] -= p[j];
			}
		}
	}
}
//找出最优解
//循环很多,最好自己能在纸上画画,还是就是防止越界
//有时候眼睛看不出来的时候,可以调试下
void bag(int *p, int num, int total)
{
	int temp = 0;	//临时保持背包的总重量
	int count = 0;	//解的个数
	int sum = 0;
	//找到每个最优解
	while (1){
		//排列组合定理,2^n == Cn^0+Cn^1+...+Cn^n
		for (int i = 0; i < num; i++){//i定位每次取多少个数
			for (int j = i; j < num; j++){//j定位每次的基数
				//只取一个数,当前循环就跳过
				temp = 0;	//重置
				//根据i来取相应的i-1个数
				for (int l = 0; l < i; l++){
					temp += p[j - i + l];//j-i确定起点
				}
				sum = 0;//重置
				for (int k = j; k < num; k++){//k就具体到哪些数了
					sum += temp + p[k];
					if (total == sum){//找到一个解
						count++;
						printf("第%d种组合方式为:\n",count);
						for (int m = 0; m < i; m++){
							printf("%3d",p[j - i + m]);//输出i-1个数,从第j个位置的数开始输出
						}
						printf("%3d\n",p[k]);	//输出最后一个被选择的数
					}else if (total < sum){//从这一点开始不符合条件,跳出此次循环
						break;
					}else{//这点很关键
						
					}
					sum = 0;//重置
				}
				if (0 == i){
					j = num;//此时当前循环结束
				}
			}
		}
		if (0 == count){//如果找不出一种组合,就--total,反正就是要找出一种最大的组合方式把
			--total;
		}else
			break;
	}
}
int main(void)	
{
	int total,num,*p;
	int sum = 0;
	//总量
	printf("请输入背包能承受的总重量\n");
	scanf("%d",&total);
	printf("请输入物品的个数\n");
	scanf("%d",&num);
		
	p = (int *)malloc(sizeof(int)*num);
	if (NULL == p){
		perror("malloc failed");
		exit(1);
	}
		
	printf("请分别输入物品的总量\n");
	for (int i = 0; i < num; i++){
		scanf("%d",p + i);
		sum += *(p + i);
	}
	printf("背包能装的下最大重量物品的组合方式为:\n");
	if (total >= sum){
		for (int i = 0; i < num; i++)
			printf("%4d",*(p + i));
		printf("\n");
	}else{	//
		sort(p, num);
		if (total < p[0]){
			printf("背包太小,容不下你的物品\n");
		}else
			bag(p, num, total);
	}
	free(p);
	p = NULL;
	return 0;
}


评论 4
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值