部分背包问题(贪心算法)

主要算法

背包问题是贪心和动态规划的经典问题,这里学习一下部分背包问题的解法。 

部分背包问题常用贪心解决,其贪心策略为优先选取单位重量价值最大的商品(介绍完算法再来看一下为什么),下面先看一下主要算法。

部分背包问题(贪心算法)_第1张图片

 这个算法也比较简单,优先选择单位重量价值的商品,用x【】数组记录是把该商品全部拿走还是只取部分即可。

至于Sort函数,需要自己写,后面的代码有,可以简单看一下。

算法实例应用

部分背包问题(贪心算法)_第2张图片 

 以上问题笔者经过计算,结果分别为:

(1)选取商品为:D + F + B + E + 35/60*C 

重量:50 +10 +30 +25 +35 = 150

价值:50 + 40 + 40 +30 +30 + 17.5 = 167.5

(2)选取商品为:F +G + B + A +E +10/50*D

重量:10 + 25 +30 + 35 +40 +10 = 150

价值:40 + 30 +40 +10 + 35 +10 = 165

(3)选取商品为:F + B + G + D + 35/40*E

重量:10 + 30 + 25 +50 +35 = 150

价值: 40 +40 +30 + 50 +30.625 = 190.625

显然,以上三种贪心策略中,每次选取单位重量价值最大的物品装入背包可得到最大价值!

(为了证明算法的正确性,还必须证明背包问题具有贪心选择性质。)

部分背包问题的贪心策略的正确性证明

贪心策略是:总是优先选择单位重量下价值最大的物品

正确性证明 是:使用该贪心策略,可以获得最优解。在这里,最优解就是带走的物品价值最大。

证明思路:先考察一个全局最优解,然后对该解加以修改(一般是采用“剪枝”技巧),使其采用贪心选择,这个选择将原问题变成一个相似的、但是更小的问题。

先假设 物品集合S={W1,W2....Wn}已经按 单位重量价值从小到大排好序了。

并假设 一个全局最优解是:S(i)={Wi1,Wi2,.....Win}。Wi1,Wi2,.....Win是有序的。对于贪心选择而言,总是会优先 选择 Wn 的物品,当Wn 没有后,再选择Wn-1 .....

如果Win = Wn 问题已经得证。因为,我们的最优解S(i)中,已经包含了贪心选择。只要继续归纳下去,Wi(n-1) 就是 Wn-1 ....

如果Win != Wn 运用剪枝技巧,剪掉Win 并 贴上 Wn  此时,得到的是一个更优的解(因为价值更大了 ,Wn > Win)。因为,Wn 是单位重量价值最高的那个物品啊,我们的贪心选择应该选择它,但是这里的最优解S(i)却没有选择它,于是我们用剪枝技巧,将它加入到S(i)中去,并把S(i)中的Win除去。  

这就证明了,如果用贪心策略来进行选择,得到的是最优解。从而证明了贪心算法的正确性。

其实,也就是证明了一定存在一个最优解,这个最优解就是由贪心选择组成的。

代码的实现

ok,废话bb一大堆,上代码让大家瞧瞧 

#include
using namespace std;
const int maxn = 1000;
float z[maxn];

void Sort(int n,float w[],float v[]){
	for(int i=0;icarrymax)	break;
		x[i] = 1;	//x[]数组用来记录此次是否选择商品,1代表全部拿走,0代表不拿,小数代表部分拿 
		carrymax -= w[i];
	}
	if(i<=n-1)  x[i] = carrymax/w[i]; 
} 


int main(){
	int n;
	float carry=0; 
	float carrymax,v[maxn],w[maxn],x[maxn];//w[],每个商品的重量,v[]代表每个商品的价值,carrymax代表最大容量 
	memset(x,0,sizeof(x));
	cout<<"请输入最大容量:";
	cin>>carrymax;
	cout<<"请输入商品数量:";
	cin>>n;
	cout<<"请输入每个商品的重量和价值:"<>w[i]>>v[i];
	}
	fire(n,w,v,x,carrymax);
	for(int i=0;i

 

你可能感兴趣的:(贪心算法,背包问题)