简单背包问题

简单背包问题

题目描述:

给定n种物品和一背包。物品***i***的重量(体积)是***wi***,其价值为***vi***,背包的容量为***C***。问:应如何选择装入背包的物品,使得装入背包中物品的总价值最大。

另一种描述形式:

image-20211105191202794

思路

一个优化问题,怎么解决呢?

最容易想到的是 枚举法,即:把所有能放进背包的方案都测试一遍,看看哪个价值最大。这里的方案指的是:选哪几个Xi(物品),注意选择的物品总个数和选哪个都是不固定的

然后有num个物品,那有多少种可能的方案呢?

当然是每个物品选或者不选2种情况,N个物品就是 2 N u m 2^{Num} 2Num种方案。

怎么表示每个方案呢?

可以用一个数字来表示 假设有8个物品,则对应于 0 − 127 ( 2 8 − 1 ) 0-127(2^8-1) 0127(281)的所有数字。为什么?

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 2n1) {
将 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;
}
  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

Tototototorres

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值