貪心法——揹包問題【通俗易懂】
阿新 • • 發佈:2019-01-09
貪心法——揹包問題
今天總結了一下演算法問題中的貪心法,用了一個揹包問題的例子,希望可以鞏固一下自己學到的知識。
一、概述
貪心法把一個複雜問題分解為一系列較為簡單的區域性最優選擇,每一步選擇都是對當前的一個擴充套件,直到獲得問題的完整解。
二、適用範圍
典型應用是求解最優化問題,而且對許多問題都能得到整體最優解。
注意:由於貪心法並不是從整體最優考慮,它所做出的選擇只是在某種意義上的區域性最優,這種區域性最優選擇並不總獲得整體最優解,但通常能獲得近似最優解。
三、揹包問題
【問題】
給定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;
}