数据结构-背包问题

实验 3


学院:数据科学与计算机学院
【实验内容】
背包问题: 假设有一个能装入总体积为 T 的背包和 n 件体积分别为 W1,W2,…, Wn 的物品, 能 否 从 n 件物品中挑选若干件恰好装满背包,即使 Wi1+Wi2+…Wim=T,要求找出所有满足上述条件的解。例如,当 T=10,各件物 品的体积为{1,8,4,3,5,2}时,可找到 4 组解: (1,4,3,2), (1,4,5), (8,2), (3,5,2)。
【数据结构与算法】
堆栈、递归思想、利用堆栈将递归转换成非递归的解决方法
【实验步骤】 1.先处理好数据读入 2.用 left 标记背包剩余容量,用 i 标记当前处理到的物品,用栈 s 存储需 要放进书包里的物品。 3.在循环里处理数据,当判断到处理完毕,用 break 退出循环。 4.(3)中循环中,先判断 i 物品能否放入背包,能则压进栈 s 里,然后判断 剩余容量 left 是否为 0,若为 0,输出结果,并且使栈 s 和 i 为下一情况,若不 为 0,则通过进一步判断决定 i 的值和栈 s 的状态。
【实验结果】
1.题目例子
这里写图片描述
2、另外举例
这里写图片描述
3、无解的输入(背包体积过大)
这里写图片描述
4、无解的输入(物品质量太大)
这里写图片描述

代码

#include<iostream>
#include<cstdlib>
#include <stack>
#define max 1000
using namespace std;
int main() {
    // read the datas
    int T, n;
    int W[max];
    bool found = false;
    cout << "please enter the capacity of the backpack : ";
    cin >> T;
    cout <<endl << "please enter the number of things(less than 1000) : ";
    cin >> n;
    cout <<endl << "please enter the weight of each things : " <<endl;
    for (int j = 0; j < n; j++) cin >> W[j];
    cout << endl << "the answer is: " << endl;

    // process
    int left = T;
    stack<int> s;
    int i = 0;

    while (1) {
        if (left == W[i] || (left > W[i] && i < n)) {  // 可以放进背包的情况 
            s.push(i);
            left -= W[i];
        }

        if (left == 0) {  // 刚好装满
            // 标记
            found = true;
            // 输出结果 
            stack<int> t;
            while (!s.empty()) {
                t.push( s.top());
                s.pop();
            }
            cout << "( ";
            while (!t.empty()) {
                cout << W[t.top()] << " ";
                s.push(t.top());
                t.pop();
            }
            cout << ")" <<endl;

            // 处理下一情况
            if (s.size() == 1) {
                left += W[s.top()];
                s.pop();
                i++;
                if (i == n) break;
            } else if (i == n-1) {
                left += W[s.top()];
                s.pop();
                i = s.top() + 1;
                left += W[s.top()];
                s.pop();
            } else {
                i = s.top() + 1;
                left += W[s.top()];
                s.pop();
            }
        } else {  // 不能装满 
            if (i == n-1) {  // i遍历到最后一个物品 
                if (s.size() == 1 && s.top() == n - 1) {
                    break;
                } else {
                    if (i == s.top()) {
                        left += W[s.top()];
                        s.pop();
                        i = s.top() + 1;
                        left += W[s.top()];
                        s.pop();
                    } else {
                        i = s.top() + 1;
                        left += W[s.top()];
                        s.pop();
                    }
                }
            } else {  // 其他情况 
                i++;
            }
        }
    }
    if (found == false) cout << "No answer." << endl;
    system("pause");
    return 0;
}
  • 6
    点赞
  • 27
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
问题描述: 假设一个装入体积为T的背包和n体积分别为w1 , w2 , … , wn物品,能否从n物品中挑选若干恰好装满背包,即使w1 +w2 + … + wn=T,要求找出所有满足上述条的解。例如:当T=10,各物品体积{1,8,4,3,5,2}时,可找到下列4组解: (1,4,3,2) (1,4,5) (8,2) (3,5,2)。 问题提示: 可利用回溯法的设计思想来解决背包问题。首先将物品排成一列,然后顺序选取物品装入背包假设已选取了前i 物品之后背包还没有装满,则继续选取第i+1物品,若该物品"太大"不能装入,则弃之而继续选取下一,直至背包装满为止。但如果在剩余的物品中找不到合适的物品以填满背包,则说明"刚刚"装入背包的那物品"不合适",应将它取出"弃之一边",继续再从"它之后"的物品中选取,如此重复,直至求得满足条的解,或者无解。 题目之二: 问题描述: 假设有n物品,这些物品的重量分别是W1 , W2 , … , Wn物品的价值分别是V1,V2, …,Vn。求从这n物品中选取一部分物品的方案,使得所选中的物品重量不超过限定的重量W(W<∑Wi, i=1,2,┅,n),但所选中的物品价值之和为最大。 问题提示: 利用递归寻找物品的选择方案。假设前面已有了多种选择的方案,并保留了其中价值最大的方案于数组option[]中,该方案的价值保存于变量max_value中。当前正在考察新方案,其物品选择情况保存于数组eop[]中。假设当前方案已考虑了i-1物品,现在要考虑第i物品:当前方案已包含的物品的重量之和为tw;因此,若其余物品都选择是可能的话,本方案所能达到的价值的期望值设为tv。引入tv是当一旦当前方案的价值的期望值也小于前面方案的价值max_value时,继续考察当前方案已无意义,应终止当前方案而去考察下一个方案。 第i物品的选择有两种可能: ① 物品i被选择。这种可能性仅当包含它不会超过方案重量的限制才是可行的。选中之后继续递归去考虑其余物品的选择; ② 物品i不被选择。这种可能性仅当不包含物品i也有可能找到价值更大的方案的情况。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值