贪心法求解背包问题

问题描述

设有编号为1、2、…、n的n个物品,它们的重量分别为w1、w2、…、wn,价值分别为v1、v2、…、vn,其中wi、vi(1≤i≤n)均为正数。
有一个背包可以携带的最大重量不超过W。求解目标:在不超过背包负重的前提下,使背包装入的总价值最大(即效益最大化),与0/1背包问题的区别是,这里的每个物品可以取一部分装入背包。

问题求解

这里采用贪心法求解。设xi表示物品i装入背包的情况,0≤xi≤1。根据问题的要求,有如下约束条件和目标函数:
贪心法求解背包问题_第1张图片
于是问题归结为寻找一个满足上述约束条件,并使目标函数达到最大的解向量X={x1,x2,…,xn}。
贪心策略:选择单位重量价值最大的物品。
每次从物品集合中选择单位重量价值最大的物品,如果其重量小于背包容量,就可以把它装入,并将背包容量减去该物品的重量,然后就面临了一个最优子问题——它同样是背包问题,只不过背包容量减少了,物品集合减少了。
因此背包问题具有最优子结构性质。

代码

int n = 5;
double W = 100;
struct NodeType
{
     
	double w;
	double v;
	double p;
	bool operator<(const NodeType &s)const
	{
     
		return p > s.p;
	}
};

NodeType A[] = {
      {
     0},{
     10,20},{
     20,30},{
     30,66},{
     40,40},{
     50,60} };
double V;
double x[MAXN];

void Knap()
{
     
	V = 0;
	double weight = W;
	memset(x, 0, sizeof(x));
	int i = 1;

	while (A[i].w < weight)//物品可以全部装入
	{
     
		x[i] = 1;
		weight -= A[i].w;
		V += A[i].v;
		i++;
	}

	if (weight > 0)//余下物品重量大于0
	{
     
		x[i] = weight / A[i].w;
		V += x[i] * A[i].v;
	}
}

算法证明

假设对于n个物品,按vi/wi(1≤i≤n)值递减排序得到1、2、…、n的序列,即v1/w1 ≥ v2/w2 ≥ … ≥ vn/wn。设X={x1,x2,…,xn}是本算法找到解。
如果所有的xi都等于1,这个解明显是最优解。否则,设minj是满足xminj<1的最小下标。考虑算法的工作方式,很明显,当iminj时,xi=0,并且。设X的价值为V(X)=在这里插入图片描述
贪心法求解背包问题_第2张图片
当i 当i>minj时,xi=0,所以xi-yi≤0,且vi/wi≤vminj/wminj。
当i=minj时,vi/wi=vminj/wminj。
贪心法求解背包问题_第3张图片
这样与Y是最优解的假设矛盾,也就是说没有哪个可行解的价值会大于V(X),因此解X是最优解。

算法分析

排序的时间复杂性为O(nlog2n),while循环的时间为O(n),所以本算法的时间复杂度为O(nlog2n)。

你可能感兴趣的:(算法,算法,贪心算法,c++)