动态规划01背包问题求解(附c/cpp代码)


1. 问题描述

有 n 种物品和一个容量是 y 的背包,每种物品只有一件。

第 i 种物品的体积是 wi,价值是 vi。

求解将哪些物品装入背包,可使这些物品的总体积不超过背包容量,且总价值最大。
输出最大价值和物品序号。


2. 输入格式

第一行两个整数,N,Y,用空格隔开,分别表示物品种数和背包容积。

接下来有 N 行,每行两个整数wi,vi,用逗号隔开,分别表示第 i 种物品的体积和价值。


3. 输出格式

输出最大价值,物品序列号。


4. 输入样例

3,10
5,8
8,20
4,17

5. 输出样例

最大价值:25
物品序号:3号 1号 

6. 问题分析

请添加图片描述


请添加图片描述


请添加图片描述


7. 代码实现

#include <iostream>
#include <bits/stdc++.h>
using namespace std;

typedef struct {
    int w;
    int v;
}Object;

int main(){
    int n,y;
    char ch;
    cin>>n>>ch>>y;
    Object ob[n+1];
    for(int i=1;i<=n;++i)
        cin>>ob[i].w>>ch>>ob[i].v;//ob[0]未使用
    int arr[n+1][y+1];
    for(int i=0;i<y+1;++i)
        arr[0][i] = 0;
    for(int i=0;i<n+1;++i)
        arr[i][0] = 0;
    for(int i=1;i<n+1;++i)
        for(int j=1;j<y+1;++j){
            arr[i][j] = arr[i-1][j];
            if(ob[i].w <= j)
                arr[i][j] = max(arr[i-1][j],arr[i-1][j-ob[i].w]+ob[i].v);
        }
    vector <int> r;
    int j = y;
    for(int i=n;i>0;--i)
        if (arr[i][j] != arr[i-1][j]){
            r.push_back(i);
            j = j - ob[i].w;
        }
    cout<<"最大价值:"<<arr[n][y]<<endl<<"物品序号:";
    for(vector<int>::iterator it = r.begin();it!=r.end();++it)
        cout<<*it<<"号 ";
    return 0;
}

8. 执行结果

10,30
2,3
5,6
8,6
10,12
6,7
9,11
4,7
6,8
7,8
5,8
最大价值:41
物品序号:107641Process returned 0 (0x0)   execution time : 1.365 s
Press any key to continue.

——————END-2022-04-23——————
———————感谢您的阅读—————————

  • 4
    点赞
  • 22
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论
以下是使用分支限界法求解0/1背包问题C++代码: ```cpp #include <iostream> #include <algorithm> #include <queue> #include <vector> using namespace std; struct Node { int level; int profit; int weight; double bound; }; bool operator<(const Node& a, const Node& b) { return a.bound < b.bound; } double bound(Node u, int n, int W, vector<pair<int, int>>& items) { if (u.weight >= W) { return 0; } double profitBound = u.profit; int j = u.level + 1; int totalWeight = u.weight; while ((j < n) && (totalWeight + items[j].second <= W)) { totalWeight += items[j].second; profitBound += items[j].first; j++; } if (j < n) { profitBound += (W - totalWeight) * (double)items[j].first / items[j].second; } return profitBound; } int knapsack(int n, int W, vector<pair<int, int>>& items) { priority_queue<Node> pq; Node u, v; pq.push({-1, 0, 0, 0}); int maxProfit = 0; while (!pq.empty()) { u = pq.top(); pq.pop(); if (u.level == n - 1) { continue; } v.level = u.level + 1; v.weight = u.weight + items[v.level].second; v.profit = u.profit + items[v.level].first; if (v.weight <= W && v.profit > maxProfit) { maxProfit = v.profit; } v.bound = bound(v, n, W, items); if (v.bound > maxProfit) { pq.push(v); } v.weight = u.weight; v.profit = u.profit; v.bound = bound(v, n, W, items); if (v.bound > maxProfit) { pq.push(v); } } return maxProfit; } int main() { int n = 4; int W = 10; vector<pair<int, int>> items = {{40, 2}, {30, 5}, {50, 10}, {10, 5}}; int result = knapsack(n, W, items); cout << "Maximum profit: " << result << endl; return 0; } ``` 在上面的代码中,我们首先定义了一个结构体`Node`,其中包含了四个成员变量`level`、`profit`、`weight`和`bound`,分别表示当前节点在决策树中的层数、当前的利润、当前的重量和当前节点的上界。另外,我们还定义了一个小于号运算符,用于将结构体按照上界从小到大排序。 然后,我们定义了一个`bound`函数,用于计算当前节点的上界。在计算上界的过程中,我们首先判断当前节点的重量是否超出了背包的容量,如果是的话,直接返回0。否则,我们将当前节点的利润作为上界的初始值,然后从当前节点的下一个节点开始,依次加入物品,直到背包装满或者物品加完为止。如果还有剩余的空间,我们按照单位重量的价值将剩余的物品加入背包,然后返回计算出的上界。 接下来,我们定义了一个`knapsack`函数,用于求解0/1背包问题。在函数中,我们首先定义了一个优先队列`pq`,用于保存当前还未扩展的节点。然后,我们将根节点加入队列中。之后,我们不断从队列中取出上界最小的节点并进行扩展,如果当前节点已经是叶子节点,则直接跳过。否则,我们分别计算出将当前节点的下一个节点加入背包和不加入背包的两种情况下的上界,并将对应的节点加入队列中。如果当前节点的上界已经小于已知的最大利润,则直接跳过。如果队列为空时,我们已经搜索完了整个决策树,此时的最大利润即为问题的解。 最后,我们在`main`函数中调用`knapsack`函数求解0/1背包问题,并输出结果。

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

打赏作者

苡荏

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

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

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

打赏作者

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

抵扣说明:

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

余额充值