我是靠谱客的博主 清秀往事,最近开发中收集的这篇文章主要介绍0-1背包问题(回溯法),觉得挺不错的,现在分享给大家,希望可以做个参考。

概述

题目描述

一个旅行者有一个背包容积为m的背包,现在有 n 件物品,它们的重量分别是W1,W2,…,Wn,它们的价值分别为V1,V2,…,Vn,求旅行者能获得最大总价值。

算法分析

用回溯法解0-1背包问题,算法步骤如下:

  1. 确定问题的解空间,本题是为了从n个物品的集合中找出总价值最大且满足约束条件的一组物品选择方案。对于第i个物品,有且仅有两种选择,即放入背包或者不放入背包,用0和1表示。所以解空间为子集树,共有 2 n 2^n 2n个解。

  2. 确定剪枝函数,将不满足约束条件和限界条件的解给去掉

    约束条件: Σ i = 1 n w i x i Sigma_{i=1} ^ n w_i x_i Σi=1nwixi <= m

    限界条件: 对于 x i x_i xi而言,前i-1个物品选择的价值已经确定,如果 ( x i + 1 , x i + 2 , . . . , x n ) (x_{i+1}, x_{i+2}, ... , x_{n}) (xi+1,xi+2,...,xn)的总价值小于等于当前的最大价值减去前i-1个物品产生的价值,就说明当前的搜索路径不可能产生最优解,可以直接剪枝。

  3. 从根节点出发,以深度优先搜索的方式遍历整个解空间。

C++代码如下

#include <iostream>
#include <vector>
#include <utility>

using std::cin;
using std::cout;
using std::endl;
using ivec = std::vector<int>;
using pair = std::pair<int, int>;
using pvec = std::vector<pair>;


int n;                              //  物品种类数
int capacity;                       //  背包容积
int maximum_val = 0;                //  最大价值


bool satisfy_bound(int flag, int before_sum, pvec &list) {
    int rest_sum = 0;
    for (int i = flag; i <= n; ++i) rest_sum += list[i].first;
    // cout << ((rest_sum > (maximum_val - before_sum)) ? true : false) << endl;
    return (rest_sum > (maximum_val - before_sum)) ? true : false;
}

void backtrack(int i, int weight, int sum, pvec &list, ivec &is_selected) {
    if (i > n) {        
        //  i > n,说明已经搜索到了叶子结点,此时得到了一个可行解,判断该解是否比当前最大值要大
        maximum_val = (maximum_val < sum) ? sum : maximum_val;
    } else {
        if (satisfy_bound(i, sum, list)) {  //  判断是否满足限界条件
            if (weight >= list[i].second) { //  判断是否满足约束条件
                is_selected[i] = 1;
                sum += list[i].first;
                backtrack(i + 1, weight - list[i].second, sum, list, is_selected);
                is_selected[i] = 0;
                sum -= list[i].first;
                backtrack(i + 1, weight, sum, list, is_selected);
            } else {                        //  剪枝
                backtrack(i + 1, weight, sum, list, is_selected);
            }
        }
    }
}

int main() {
    cin >> n >> capacity;
    auto list = pvec(n+1);              //  存放每一种物品,first为价值、second为重量
    auto is_selected = ivec(n+1, 0);    //  记录每一个物品是否被选中,选中为1,未中为0
    for (int i = 1; i <= n; ++i) cin >> list[i].first >> list[i].second;
    backtrack(1, capacity, 0, list, is_selected);
    cout << "最优解为:" << maximum_val << endl;
    return 0;
}

测试数据

输入:
5 6
2 1
4 2
4 3
5 4
6 5

输出:
10

最后

以上就是清秀往事为你收集整理的0-1背包问题(回溯法)的全部内容,希望文章能够帮你解决0-1背包问题(回溯法)所遇到的程序开发问题。

如果觉得靠谱客网站的内容还不错,欢迎将靠谱客网站推荐给程序员好友。

本图文内容来源于网友提供,作为学习参考使用,或来自网络收集整理,版权属于原作者所有。
点赞(60)

评论列表共有 0 条评论

立即
投稿
返回
顶部