贪心法求解部分背包问题

背包问题:给定一个载重为M的背包,及n个质量为Wi、价值为Pi的物体,1<=i<=n,要求把物体装满背包,且使得背包内的物体价值最大。

假设:Xi是物体i被装入背包的部分,0<=Xi<=1。当Xi=0时,表示物体i没有被装入背包;当Xi=1时,表示物体i被全部装入背包;当Xi处于0~1之间,表示物体i的一部分被装入背包。根据问题的要求,可以列出下列的约束方程和目标函数:

												![在这里插入图片描述](https://img-blog.csdnimg.cn/20201124220348273.png?x-oss-process=image/watermark,type_ZmFuZ3poZW5naGVpdGk,shadow_10,text_aHR0cHM6Ly9ibG9nLmNzZG4ubmV0L1ZhbGVuZGlh,size_16,color_FFFFFF,t_70#pic_center)

于是,问题归结为寻找一个满足约束方程并使目标函数达到最大的解向量X=(X1,X2,X3…Xn)
为使目标函数的值增加最快,一种方法是优先选择价值最大的物体装入背包,这样当最后一个物体装不下时,选择一个适当的Xi<1的物体装入,把背包装满。但是,使用这种方法,不一定能够达到最准的目的。如果所选择的物体重量很大,使得背包载重量的消耗速度太快,以致后续能够装入背包的物体迅速减少,从而便得继续装入背包的物体在满足了约束力程的要求以后,无法达到目标函数的要求。因此,最好是选择既使目标函数的值增加最快,又使背包载重量的消耗较慢的物体装入背包。达到这个目的的一种方法是优先选择价值重量比最大的物体装入背包。基于上述考虑,定义下面的数据结构:

typedef struct{
	float p;//物体的价值
	float w;//物体的质量
	float v;//物体的价值质量比
}WP;
WP instance[MAX];
float x[MAX];

/*
贪婪发求解背包问题
输入:背包载重M,存放物品的价值p、质量m信息的数组instance[  ],物体的数量n
输出:n个物体被装入背包的分量x[i],背包中物体的总价值p
*/
float knapsack_greedy(float M,WP instance[],float x[],int n){
	int i=0;
	float m,p=0;
	for(i=0;i<n;i++){
		instance[i].v=instance[i].p/instance[i].w; //计算每个物品的价值质量比
		x[i]=0;
	}
	mysort(instance,n);
	m=M;
	for(i=0;i<n;i++){ //依次装入价质比高的物品,直到某一刻超过背包可以载重的范围
		if(instance[i].w<=m){
			x[i]=1;
			printf("价质比为%f的物体被取走%f\n",instance[i].v,x[i]);
			m=m-instance[i].w; //背包此时可以载重的重量减少
			p=p+instance[i].p; //背包此时的最大价值增加
		}
		else{ 
			x[i]=m/instance[i].w;//分割物品,物体的部分被装入背包
			printf("价质比为%f的物体被取走%f\n",instance[i].v,x[i]);
			p=p+x[i]*instance[i].p;
			break;
		}
	}
	return p;
}

完整程序代码:

#include<stdio.h>
#define MAX 100
typedef struct{
	float p;//物体的价值
	float w;//物体的质量
	float v;//物体的价值质量比
}WP;
WP instance[MAX];
float x[MAX];

void mysort(WP instance[],int n){
	int i=0,j=0;

	for(i=0;i<n-1;i++)
		for(int j=i+1;j<n;j++)
			if(instance[i].v<instance[j].v){
				WP temp=instance[i];
				instance[i]=instance[j];
				instance[j]=temp;
			}
	printf("输出排序后的物品的\n");
	printf("价值\t\t");printf("质量\t\t");printf("价质比\n");
	for(i=0;i<n;i++)
		printf("%f\t%f\t%f\n",instance[i].p,instance[i].w,instance[i].v);
	printf("\n");
}

/*
贪婪发求解背包问题
输入:背包载重M,存放物品的价值p、质量m信息的数组instance[  ],物体的数量n
输出:n个物体被装入背包的分量x[i],背包中物体的总价值p
*/
float knapsack_greedy(float M,WP instance[],float x[],int n){
	int i=0;
	float m,p=0;
	for(i=0;i<n;i++){
		instance[i].v=instance[i].p/instance[i].w; //计算每个物品的价值质量比
		x[i]=0;
	}
	mysort(instance,n);
	m=M;
	for(i=0;i<n;i++){ //依次装入价质比高的物品,直到某一刻超过背包可以载重的范围
		if(instance[i].w<=m){
			x[i]=1;
			printf("价质比为%f的物体被取走%f\n",instance[i].v,x[i]);
			m=m-instance[i].w; //背包此时可以载重的重量减少
			p=p+instance[i].p; //背包此时的最大价值增加
		}
		else{ 
			x[i]=m/instance[i].w;//分割物品,物体的部分被装入背包
			printf("价质比为%f的物体被取走%f\n",instance[i].v,x[i]);
			p=p+x[i]*instance[i].p;
			break;
		}
	}
	return p;
}

int main(void){
	WP Obj[MAX]={0};
	float p=0;
	int i=0;
	int nwp=MAX; //物品的最大数量
	float c=MAX; //背包可以承载的最大质量

	printf("请输入背包可以承载的重量:");
	scanf("%f",&c);
	printf("请输入物品的总数量:");
	scanf("%d",&nwp);
	printf("\n");
	printf("请输入物体的:\n"); //只是为了看得方便
	printf("价值\t");printf("质量\n");

	for(i=0;i<nwp;i++)	//输入每个物品的价值和质量
		scanf("%f%f",&Obj[i].p,&Obj[i].w);

	p=knapsack_greedy(c,Obj,x,nwp);
	printf("该背包的最大价值是%f\n",p);

	return 0;
}

运行结果:
在这里插入图片描述

  • 7
    点赞
  • 40
    收藏
    觉得还不错? 一键收藏
  • 2
    评论
部分背包问题是指,有一个背包容量为C,有n个物品,每个物品有一个重量wi和一个价值vi,可以取走物品的一部分,求背包所能装下的最大价值。 贪心法求解部分背包问题的思路是,按照每个物品的单位重量价值从大到小排序,然后依次装入物品,直到背包装满为止。如果当前物品无法完全装入背包,则将其部分装入,直到背包装满。 以下是部分背包问题C语言代码实现: ```c #include <stdio.h> #include <stdlib.h> typedef struct { double weight; // 物品重量 double value; // 物品价值 double unit_value; // 物品单位重量价值 } Item; // 按照物品单位重量价值从大到小排序 int cmp(const void *a, const void *b) { Item *item1 = (Item *)a; Item *item2 = (Item *)b; return (item2->unit_value - item1->unit_value) > 0 ? 1 : -1; } int main() { int n = 5; // 物品数量 int C = 10; // 背包容量 Item items[n]; items[0] = (Item){2, 6, 0}; items[1] = (Item){2, 3, 0}; items[2] = (Item){6, 5, 0}; items[3] = (Item){5, 4, 0}; items[4] = (Item){4, 6, 0}; // 计算每个物品的单位重量价值 for (int i = 0; i < n; i++) { items[i].unit_value = items[i].value / items[i].weight; } // 按照物品单位重量价值从大到小排序 qsort(items, n, sizeof(Item), cmp); double value = 0; // 背包所能装下的最大价值 int i = 0; // 当前物品下标 while (C > 0 && i < n) { if (C >= items[i].weight) { value += items[i].value; C -= items[i].weight; } else { value += C * items[i].unit_value; C = 0; } i++; } printf("背包所能装下的最大价值为%f\n", value); return 0; } ``` 在实现中,首先定义了一个Item结构体来存储物品的重量、价值和单位重量价值。然后计算每个物品的单位重量价值,并按照从大到小的顺序排序。最后依次取出每个物品,如果能够完全装入背包,则将其全部装入;否则,将其部分装入,直到背包装满为止。最终输出背包所能装下的最大价值。
评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值