贪心法——背包问题
今天总结了一下算法问题中的贪心法,用了一个背包问题的例子,希望可以巩固一下自己学到的知识。
一、概述
贪心法把一个复杂问题分解为一系列较为简单的局部最优选择,每一步选择都是对当前的一个扩展,直到获得问题的完整解。
二、适用范围
典型应用是求解最优化问题,而且对许多问题都能得到整体最优解。
注意:由于贪心法并不是从整体最优考虑,它所做出的选择只是在某种意义上的局部最优,这种局部最优选择并不总获得整体最优解,但通常能获得近似最优解。
三、背包问题
【问题】
给定n个物品和一个容量为C的背包,物品i的重量是wi,其价值为vi,背包问题是如何选择装入背包中物品的总价值最大。
【分析】
在贪心算法中,背包问题可以有三种思路,
第一种就是直接按照物品的价值,从价值最大的开始往背包里面装,直到达到背包容量。
第二种就是直接按照物品的重量,从重量最小的开始往背包里面装,直到达到背包容量。
显然上面的两种办法都没有能力满足背包问题的最优解,因为它只是单方面的考虑的价值的增长或容量的消耗,其实最好的想法是按照单位重量的价值,往背包里面装物品。这个是比较合理的一个做法。
【算法】
设背包容量为C,且共有n个物品,物品重量存放在数组w[n]中,价值存放在数组v[n]中,问题的解存放在数组x[n]中。
第一步要做的事情是按照单位重量价值v[i]/w[i]降序排列。这里使用了一个冒泡排序:
#include<stdio.h>
int main(){
int a[10];
int i,j,t;
for(i=0;i<10;i++)
{
scanf("%d",&a[i]);
}
for(i=1;i<10;i++)
for(j=0;j<10-i;j++) //比较一轮将一个较大的数沉底
if(a[j]>a[j+1]) // 两两进行比较,降序是 < 升序是 >
{
t=a[j];a[j]=a[j+1];a[j+1]=t;
}
for(i=9;i>=0;i--)
printf("%4d",a[i]);
return 0;
}
第二步就是将获得的解的数组x[n]初始化为0;并且按照下面的代码进行循环,往背包里面装东西,直到要装进去的物品的w[i]超过了背包的剩余容量。
int x[n] = {0};
int maxValues = 0; //装入背包的物品的总价值
int i;
for( i=0 ;w[i]<C;i++)
{
x[i] = 1; //说明第i+1个物品放入到背包
maxValue += v[i];
C = C - w[i];
}
第三步就是将背包剩余的容量装满,虽然它可能装不下一整个物品。
x[i] =(double) C/w[i]; //第i+1个物品装入的比例
maxValue += x[i]*v[i]; //装入背包的物品的总价值
贪心法背包问题的C++代码:
#include<iostream>
using namespace std;
int KnapSack(int w[],int v[], int count,int C){
double x[10] ={0} ;
int maxValue = 0;
for(int j = 1;j<count;j++){
for(int i = 0;i<count-j;i++)
{
double temp;
double t1 = v[i]/w[i];
double t2 = v[i+1]/w[i+1];
if(t1<t2){
temp = v[i];v[i]=v[i+1];v[i+1]=temp;
temp = w[i];w[i]=w[i+1];w[i+1]=temp;
}
}
}
for(int i=0;i<3;i++) //展示一下排序结果
{
cout<<"w["<<i<<"] :"<<w[i]<<" "<<"v["<<i<<"] :"<<v[i]<<endl;
}
int i;
for( i=0 ;w[i]<C;i++)
{
x[i] = 1;
maxValue += v[i];
C = C - w[i];
}
x[i] =(double) C/w[i];
maxValue += x[i]*v[i];
return maxValue;
}
int main(){
int w[3]= {20,30,10};
int v[3]= {60,120,50};
int c= 50;
int value;
value =KnapSack(w,v,3,c);
cout<<value<<endl;
return 0;
}