何为背包问题?
已知一个载重为M的背包和n件物品,第i件物品重量为w[i],若将第i件物品全部放入背包将有p[i]收益(w[i]>0 p[i]>0 0≤i<n)
背包问题分两类
- 0/1背包问题 即物品不能被分割 要么装入要么不装入
- 一般背包问题 即物品能被分割 也就是允许将一部分物品放入背包 另一部分可以不放
0/1背包无法用贪心法得到最优解 只能得到近似解 即需要用到动态规划
一般背包问题可以用贪心法求解 即选择单位重量收益最大物品装入背包 即按照p[i]/w[i]的非增次序选取物品
#include <iostream>
#include <cstdlib>
/* run this program using the console pauser or add your own getch, system("pause") or input loop */
const int maxn=1e3+2;
int w[maxn],p[maxn],new_w[maxn],new_p[maxn],rec[maxn];
float a[maxn],b[maxn],x[maxn]={0};
bool mark[maxn]={false};//重复标记
int cmp(const void* _a, const void* _b){
int *a=(int*)_a;
int *b=(int*)_b;
//return *a-*b;//升序
return *b-*a; //降序
}
void solve(int n,int M,float *a,int *w){
int i;
float u=M;//表剩余背包重量
for(i=0;i<n;i++){
if(w[i]>u)//放不下的情况
break;
x[i]=1.0;//放的下的情况
u=u-w[i];
}
if(i<n)
x[i]=u/w[i];
}
using namespace std;
int main(int argc, char** argv) {
int n,M;
float maxben=0;
cout<<"请输入数量:";
cin>>n;
cout<<"请输入最大承重:";
cin>>M;
cout<<"请输入"<<n<<"个重量:";
for(int i=0;i<n;i++)
cin>>w[i];
cout<<"请输入"<<n<<"个收益:";
for(int i=0;i<n;i++)
cin>>p[i];
for(int i=0;i<n;i++){
a[i]=(float)p[i]/w[i];
b[i]=(float)p[i]/w[i];
}
qsort(b,10,sizeof(float),cmp);//本质是将b数组快排
int k=0;
for(int i=0;i<n;i++){
for(int j=0;j<n;j++){
if(b[i]==a[j]&&!mark[j]){
rec[k]=j;
mark[j]=true;
k++;
break;
}
}
}
//45-54实现记录递减后的下标
for(int i=0;i<n;i++){
new_w[i]=w[rec[i]];
new_p[i]=p[rec[i]];
}
//56-59实现将w和p按p/w递减顺序重新对应
solve(n,M,b,new_w);
cout<<"重量分别为:";
for(int i=0;i<n;i++){
cout<<new_w[i]<<" ";
}
cout<<endl<<"其最优解:";
for(int i=0;i<n;i++){
cout<<x[i]<<" ";
maxben+=(x[i]*new_p[i]);
}
cout<<endl<<"其最大收益:"<<maxben<<endl;
return 0;
}
例如第一个例子
M=20 n=3
重量3元组(w0,w1,w2)=(18,15,10)
收益3元组(p0,p1,p2)=(25,24,15)
单位重量收益3元组(p0/w0,p1/w1,p2/w2)=(1.39,1.6,1.5)
Ⅰp1/w1=1.6最大 w1=15<M=20 完全放入背包 剩余w=5
Ⅱp2/w2=1.5其次 w2=10>w=5 不完全放入背包 放入w/w2=1/2
最大收益24*1+0.5*15=31.5