西南交通大学算法分析与设计实验例题7.1源码-01背包问题c++解法

实验描述

0-1背包问题的回溯法求解过程分析
设有n个物品,每个物品的重量为wi价值为pi,背包的容量为c,希望将其中的部分物品装入背包中,在不超过背包容量的情况下,希望物品的总价值最大。
输入:
输入第一行为物品数量n以及背包容量c,第2行到第n+1行,每行有两个整数wi, pi,分别表示物品的重量以及价值。

实验题目

在这里插入图片描述

实验7.1源码

#include <iostream>
using namespace std;
template <class Typep, class Typew>
Typep Knapsack(Typep[], Typew[], Typew, int); //负责对变量初始化,调用递归函数 Backtrack(1)实现回溯搜索并返回最大装包价值
template <class Typew, class Typep>
class Knap // Knap类记录解空间树的结点信息
{
    friend Typep Knapsack(Typep[], Typew[], Typew, int);

public:
    Typep Bound(int i);    //计算以当前结点为根的子树的价值上界
    void Backtrack(int i); //核心函数,对解空间树回溯搜索,求得最大装包价值
    Typew c;               //背包容量
    int n;                 //物品数
    Typew *w;              //物体重量数组
    Typep *p;              //物体价值数组
    Typew cw;              //当前重量
    Typep cp;              //当前价值
    Typep bestp;           //当前最优价值
};
template <class Typep, class Typew>
class Object //定义对象类,作用相当于结构体
{
    friend Typep Knapsack(Typep[], Typew[], Typew, int);

public:
    int operator<(Object a) const //符号重载函数,重载<符号
    {
        return d >= a.d;
    }
    int ID;  //编号
    float d; //单位重量的价值
};

template <class Typep, class Typew>
void Sort(class Object<Typep, Typew> *Q, int n); //按单位价值从大到小排序

int main() // Knapsack(p, w, c, n)
{
    int *p, *w, c, n, bestp;
    cin >> n >> c;
    p = new int[n + 1];
    w = new int[n + 1];
    for (int i = 1; i <= n; i++)
    {
        cin >> w[i] >> p[i];
    }
    bestp = Knapsack(p, w, c, n);
    cout << bestp << endl;
    return 0;
}
template <class Typew, class Typep>

void Knap<Typew, Typep>::Backtrack(int i)
{
    //如果搜索到了最后一个物品。则求出最优价值。
    if (i > n)
    {
        bestp = cp;
        return;
    }
    //如果已装物品重量+当前待装物品重量小于背包容量
    //则将其装入
    if (cw + w[i] <= c)
    {
        cw += w[i];
        cp += p[i];
        Backtrack(i + 1);
        cw -= w[i];
        cp -= p[i];
        //如果以i+1为根的子树上所有物品最大值比当前找到的最大价值要打
        //则有必要搜
    }
}
//计算当前结点处的上限,此处采用的是贪心算法
//可以证明通过算法获得的值在一般情况下是不能达到的
template <class Typew, class Typep>
Typep Knap<Typew, Typep>::Bound(int i)
{
    Typew cleft = c - cw; //背包所能承受的重量
    Typep b = cp;         //当前价值
    //在物品数量小于总物品数量以及物品重量小于背包的剩余重量时,
    //将该物品装入背包中,并增加相应价值
    while (i <= n && w[i] <= cleft)
    {
        cleft -= -w[i];
        b += p[i];
        i++;
    }
    //如果所装入物品数量小于整个物品的个数,则可装入第i个物品的部分,
    //从而达到背包能装入物品的最大价值
    if (i <= n)
        b += p[i] * cleft / w[i];
    return b;
}
template <class Typep, class Typew>
Typep Knapsack(Typep p[], Typew w[], Typew c, int n)
{
    //为Knap::Backtrack初始化
    Typew W = 0;
    Typep P = 0;
    Object<Typep, Typew> *Q = new Object<Typep, Typew>[n + 1]; //创建Object类的对象数组|
    //计算单位重量的价值,并计算总的价值和总的重量
    for (int i = 1; i <= n; i++) //初始化Object类的对象数组|
    {
        Q[i].ID = i;
        Q[i].d = 1.0 * p[i] / w[i];
        P += p[i]; //总的价值
        W += w[i]; //总的重量
    }
    //如果总的重量小于背包所承受的重量,则返回总的价值
    if (W <= c)
        return P;
    //按照单位价值的大小从大到小排序
    Sort(Q, n); //不是库函数,是自己定义的,要按照单位重量去排序
    //按照单位价值的大小从大到小的排序,并将其价值和重量并保存到p和w中
    Knap<Typew, Typep> K;
    K.p = new Typep[n + 1];
    K.w = new Typew[n + 1];
    for (int i = 1; i <= n; i++)
    {
        K.p[i] = p[Q[i].ID];
        K.w[i] = w[Q[i].ID];
    }
    K.cp = 0;
    K.cw = 0;
    K.c = c;
    K.n = n;
    K.bestp = 0;
    //搜索最优值
    K.Backtrack(1);
    delete[] Q;
    delete[] K.w;
    delete[] K.p;
    return K.bestp;
}
template <class Typep, class Typew>
void Sort(class Object<Typep, Typew> *Q, int n)
{
    int k;
    //直接插入排序算法,按到从大到小的顺序排序
    for (int i = 2; i <= n; i++)
    {
        if (Q[i].d < Q[i - 1].d)
        {
            Q[0] = Q[i]; // Q[0]=temp作用
            for (int k = i - 1; !(Q[k].d < Q[0].d); k--)
            {
                Q[k + 1] = Q[0];
            }
        }
        return;
    }
}

要求

在这里插入图片描述

在这里插入图片描述

在这里插入图片描述

算法分析

//后续补充

算法测试

// 6 80 40 50 60 70 30 40 20 30 50 60 10 20

测试结果

110

  • 1
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

打赏作者

七七喜欢你

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

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

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

打赏作者

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

抵扣说明:

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

余额充值