简单背包问题
题目描述:
给定n种物品和一背包。物品***i***的重量(体积)是***wi***,其价值为***vi***,背包的容量为***C***。问:应如何选择装入背包的物品,使得装入背包中物品的总价值最大。
另一种描述形式:
思路
一个优化问题,怎么解决呢?
最容易想到的是 枚举法,即:把所有能放进背包的方案都测试一遍,看看哪个价值最大。这里的方案指的是:选哪几个Xi(物品),注意选择的物品总个数和选哪个都是不固定的
然后有num个物品,那有多少种可能的方案呢?
当然是每个物品选或者不选2种情况,N个物品就是 2 N u m 2^{Num} 2Num种方案。
怎么表示每个方案呢?
可以用一个数字来表示 假设有8个物品,则对应于 0 − 127 ( 2 8 − 1 ) 0-127(2^8-1) 0−127(28−1)的所有数字。为什么?
0 写成二进制 = 0000 0000 每一位代表一个物品,0就是选,1不选。
例如 7 = 0000 0111 代表选择第1 2 3个物品 1 0 0 0 0 1 1 1代表选择 第 1 2 3 8个物品
之后伪代码:
for (i=0 to 2 n − 1 2^n-1 2n−1) {
将 i 对应的二进制数按位存放到数组Y中;
尝试按照装包方案y进行装包,则背包中物品的重量为CurWeight, 价值为CurValue;
如果CurWeight>C,则丢弃该方案,继续尝试下一种方案;否则,若该方案优于以前的方案,即如果CurValue>Value,则暂存该方案:即X=Y,Value=CurValue, Weight= CurWeight。 继续循环;
}
意思就是从 i = 0 t o 2 ( n ) − 1 i = 0 \,\, to \,\, 2^{(n)} - 1 i=0to2(n)−1 遍历,每一个i拆成二进制代表一个数字,然后就得到了一个方案。
把所有物品遍历,每个都看看是否选择了,计算出当前方案下的总价值以及重量,和以及记录的比,如果更优,就更新之前记录的。
最后输出。
注意 (W与V均为浮点数)
代码:(请勿直接Copy)
C++版本:
#include<iostream>
#include<bits/stdc++.h>// 一个C++的库函数 可以不用
using namespace std;
int main()
{
int bag,num;
cin>>bag>>num;//可以改成scanf
vector<float> items(num+1,0);//
vector<float> vals(num+1,0);
for(int i=1;i<=num;i++){
cin>>items[i];
}
for(int i=1;i<=num;i++){
cin>>vals[i];
}
int best_i = 0;
float ans = 0;
float finalweight = 0;
int N = pow(2,num)-1;
for(int i=0;i<=N;i++){
float curweight=0;
float val = 0;
int biti = i;
for(int j=0;j<num;j++){
if( (biti>>j)%2==1){
//选
curweight+=items[j+1];
val+=vals[j+1];
if(curweight > bag)
break;
}
}
if(curweight <= bag)
if(val > ans){
ans = val;
best_i = biti;
finalweight = curweight;
}
}
for(int i=0;i<num;i++){
if((best_i>>i) %2 == 1)
cout<<i+1<<" ";
}
printf("%d %d",(int)finalweight,(int)ans);
return 0;
}
C语言代码:
#include<iostream>
#include<math.h>
const int MAXN = 100;
int main()
{
int bag,num;
float *items,*vals;
scanf("%d%d",&bag,&num);
//动态申请一维数组
items = (float*)malloc(4*(num+1));//加1可以放着0不用
vals = (float*)malloc(4*(num+1));//加1可以放着0不用
for(int i=1;i<=num;i++){
scanf("%f",&items[i]);
}
for(int i=1;i<=num;i++){
scanf("%f",&vals[i]);
}
int best_i = 0;// 记录最好的方案 用一个数的二进制来表示
float ans = 0; // ans为最后的结果,价值
float finalweight = 0;//最后的重量
int N = pow(2,num)-1;
for(int i=0;i<=N;i++){
float curweight=0;
float val = 0;
int biti = i;// 复制
for(int j=0;j<num;j++){
if( (biti>>j)%2==1){
//这个位操作就是 把biti(写成二进制)右移一位
//看右移后 最低位是不是1 是1代表当前物品j 再该方案下选择了
//选
curweight+=items[j+1];
val+=vals[j+1];
if(curweight > bag)
break;
}
}
if(curweight <= bag)
if(val > ans){
ans = val;
best_i = biti;
finalweight = curweight;
}
}
for(int i=0;i<num;i++){
if((best_i>>i) %2 == 1)
printf("%d ",i+1);
}
printf("%d %d",(int)finalweight,(int)ans);
return 0;
}