回溯算法:0-1背包问题

回溯算法非常适合用递归来实现,在实现的过程中,剪枝操作是提高回溯效率的一种技巧。利用剪枝,我们并不需要穷举搜索所有的情况,从而提高搜索效率。
回溯算法的核心思想就是:
1:递归之前「做选择」;
2:递归之后「撤销选择」。

以下实例为0-1背包问题,背包承重极限是一定的,每个物体的价值都不一样,
1、MaxWeight 函数不计算物体价值,挑选出背包承重极限以内最大承重的组合;
2、WeightValue 函数则在满足背包承重极限的前提下,挑选出总价值最高的组合。


#include <iostream>
#include <vector>

void MaxWeightFunc(int* weight, int nLength, int nWeightLimit, int i, int nCurrentWeight, \
    int& nMaxWeight, std::vector<bool>& vec, std::vector<std::vector<bool>>& vecvec)
{
    if (nCurrentWeight > nWeightLimit) {
        return;
    }
    if (i >= nLength) {
        if (nCurrentWeight > nMaxWeight) {
            nMaxWeight = nCurrentWeight;
            vecvec.clear();
            vecvec.push_back(vec);
        } else if (nCurrentWeight == nMaxWeight) {
            vecvec.push_back(vec);
        }
        return;
    }
    vec.push_back(false);
    MaxWeightFunc(weight, nLength, nWeightLimit, i + 1, \
        nCurrentWeight, nMaxWeight, vec, vecvec);
    vec.back() = true;
    MaxWeightFunc(weight, nLength, nWeightLimit, i + 1, \
        nCurrentWeight + weight[i], nMaxWeight, vec, vecvec);
    vec.pop_back();
}

void MaxWeight(int* weight, int nLength, int nWeightLimit)
{
    std::cout << std::endl << "Source weight: " << std::endl;
    for (int i = 0; i < nLength; i++) {
        std::cout << weight[i] << ' ';
    }
    std::cout << std::endl;

    std::vector<bool> vec;
    std::vector<std::vector<bool>> vecvec;
    int nMaxWeight = 0;

    MaxWeightFunc(weight, nLength, nWeightLimit, 0, 0, nMaxWeight, vec, vecvec);

    std::cout << "Max weight: " << nMaxWeight << std::endl;
    for (auto it = vecvec.begin(); it != vecvec.end(); it++) {
        for (auto iter = it->begin(); iter != it->end(); iter++) {
            std::cout << *iter << ' ';
        }
        std::cout << std::endl;
    }
    std::cout << std::endl;
}

void WeightValueFunc(int* weight, int* value, int nLength, int nWeightLimit, int i, int nCurrentWeight, \
    int nCurrentValue, int& nMaxValue, std::vector<bool>& vec, std::vector<std::vector<bool>>& vecvec)
{
    if (nCurrentWeight > nWeightLimit) {
        return;
    }
    if (i >= nLength) {
        if (nCurrentValue > nMaxValue) {
            nMaxValue = nCurrentValue;
            vecvec.clear();
            vecvec.push_back(vec);
        } else if (nCurrentValue == nMaxValue) {
            vecvec.push_back(vec);
        }
        return;
    }
    vec.push_back(false);
    WeightValueFunc(weight, value, nLength, nWeightLimit, i + 1, \
        nCurrentWeight, nCurrentValue, nMaxValue, vec, vecvec);
    vec.back() = true;
    WeightValueFunc(weight, value, nLength, nWeightLimit, i + 1, \
        nCurrentWeight + weight[i], nCurrentValue + value[i], nMaxValue, vec, vecvec);
    vec.pop_back();
}

void WeightValue(int* weight, int* value, int nLength, int nWeightLimit)
{
    std::cout << std::endl << "Source weight: " << std::endl;
    for (int i = 0; i < nLength; i++) {
        std::cout << weight[i] << ' ';
    }
    std::cout << std::endl;
    std::cout << "Source value: " << std::endl;
    for (int i = 0; i < nLength; i++) {
        std::cout << value[i] << ' ';
    }
    std::cout << std::endl;

    std::vector<bool> vec;
    std::vector<std::vector<bool>> vecvec;
    int nMaxValue = 0;

    WeightValueFunc(weight, value, nLength, nWeightLimit, 0, 0, 0, nMaxValue, vec, vecvec);

    std::cout << "Max value: " << nMaxValue << std::endl;
    for (auto it = vecvec.begin(); it != vecvec.end(); it++) {
        for (auto iter = it->begin(); iter != it->end(); iter++) {
            std::cout << *iter << ' ';
        }
        std::cout << std::endl;
    }
    std::cout << std::endl;
}

int main()
{
    int weight[] = { 21, 58, 13, 36, 5, 18, 42, 1, 10, 8 };
    int value[] = { 4, 7, 3, 9, 1, 14, 8, 10, 5, 20 };

    MaxWeight(weight, sizeof(weight) / sizeof(weight[0]), 100);
    WeightValue(weight, value, sizeof(weight) / sizeof(weight[0]), 100);

    return 0;
}

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值