回溯应用-- 0-1背包问题

1. 问题描述

0-1背包非常经典,很多场景都可以抽象成这个问题。经典解法是动态规划,回溯简单但没有那么高效。

  • 有一个背包,背包总的承载重量是 W kg。现有n个物品,每个物品重量不等,并且不可分割。
  • 选择几件物品,装到背包中。在不超过背包所能装载重量的前提下,如何让背包中物品总重量最大?
  • 物品是不可分割的,要么装要么不装,所以叫 0-1背包问题。

2. 回溯解决思路

  • 对于每个物品来说,都有两种选择,装进背包或者不装进背包。
  • 对于n个物品来说,总的装法就有 2n 种,去掉总重量超过 W kg的,从剩下的装法中选择总重量最接近 W kg的。不过,我们如何才能不重复地穷举出这 2n 种装法呢?

可以用回溯方法。

  • 把物品依次排列,整个问题就分解为了n个阶段,每个阶段对应一个物品怎么选择。
  • 先对第一个物品进行处理,选择装进去或者不装进去,然后再递归地处理剩下的物品。
  • 当发现已经选择的物品的重量超过 W kg之后,就停止继续探测剩下的物品(搜索剪枝技巧)。
/**
 * @description: 0-1背包--回溯应用
 * @author: michael ming
 * @date: 2019/7/9 1:13
 * @modified by: 
 */
#include <iostream>
#define MaxWeight 76   //背包承载极限
using namespace std;
void fill(int i, int curWeight, int *bag, int N, int &maxweightinbag)
{
    if(curWeight == MaxWeight || i == N)//到达极限了,或者考察完所有物品了
    {
        if(curWeight > maxweightinbag)
            maxweightinbag = curWeight;//记录历史最大装载量
        return;
    }
    fill(i+1,curWeight,bag,N,maxweightinbag);//不选择当前i物品,cw不更新
    if(curWeight+bag[i] <= MaxWeight)//选择当前i物品,cw更新
    {//没有达到极限,继续装
        fill(i+1,curWeight+bag[i],bag,N,maxweightinbag);
    }
}
int main()
{
    const int N = 4;
    int bag[N] = {15,6,40,21};
//    int bag[N] = {1,2,3,4};
    int maxweightinbag = 0;
    fill(0,0,bag,N,maxweightinbag);
    cout << "最大可装进背包的重量是:" << maxweightinbag;
    return 0;
}

升级版:
每个物品对应着一种价值,求不超过背包载重极限,可装入背包的最大总价值。(在上面程序里稍加修改即可)

/**
 * @description: 
 * @author: michael ming
 * @date: 2019/7/11 20:42
 * @modified by: 
 */

#include <iostream>
#define MaxWeight 50   //背包承载极限
using namespace std;
void fill(int i, int curWeight, int curValue, int *bag,int *value, int N, int &weightinbag, int &maxValue)
{
    if(curWeight == MaxWeight || i == N)//到达极限了,或者考察完所有物品了
    {
        if(curValue > maxValue)
        {
            maxValue = curValue;//记录历史最大价值
            weightinbag = curWeight;//记录最大价值对应的重量
        }
        return;
    }
    fill(i+1,curWeight,curValue,bag,value,N,weightinbag,maxValue);//不选择当前i物品,cw,cv不更新
    if(curWeight+bag[i] <= MaxWeight)//选择当前i物品,cw,cv更新
    {//没有达到极限,继续装
        fill(i+1,curWeight+bag[i],curValue+value[i],bag,value,N,weightinbag,maxValue);
    }
}
int main()
{
    const int N = 4;
    int bag[N] = {15,6,40,21};
    int value[N] = {1,2,3,4};
    int weightinbag = 0, maxValue = 0;
    fill(0,0,0,bag,value,N,weightinbag,maxValue);
    cout << "最大可装进背包的最大价值是:" << maxValue
            << " ,对应重量是: " << weightinbag;
    return 0;
}

在这里插入图片描述

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

打赏作者

Michael阿明

如果可以,请点赞留言支持我哦!

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

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

打赏作者

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

抵扣说明:

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

余额充值