多种方法求解求解0/1背包问题之回溯法(及其详细,内附源码)

问题描述:

在这里插入图片描述

问题求解:

在这里插入图片描述

在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述

主要代码

#include <iostream>
#include<stdio.h>

using namespace std;
#define MAXN 20 //最大问题规模
//问题描述
int W = 6;
int n = 4;
int w[] = {0,5,3,2,1};
int v[] = {0,4,4,3,1};
int x[MAXN];//用于标记物品是否被选
int maxv = 0;//最大价值初始化为0、
void dfs(int i,int tw,int tv,int op[])
{
    if(i > n)
    {
        if(tw == W && tv > maxv)
        {
            maxv = tv;//保存最优解
            for(int i = 1;i <= n;i++)
                x[i] = op[i];//保存它
        }
    }
    else
    {
        op[i] = 1;//选择
        dfs(i+1,tw+w[i],tv+v[i],op);
        op[i] = 0;// 不选择
        dfs(i+1,tw,tv,op);
    }
}
int main() {
    int op[MAXN];
    dfs(1,0,0,op);
    for(int i = 1; i <= n;i++)
    {
        if(x[i] == 1)
            printf("%d ",i);
    }
    printf("\n");
    printf("最大价值为:%d",maxv);
    return 0;
}

回溯法解0_1背包问题时,会用到状态空间树。在搜索状态空间树时,只要其左儿子结点是一个可行结点,搜索就进入其左子树。当右子树有可能包含最优解时才进入右子树搜索,否则将右子树剪去。设r是当前剩余物品价值总和;cp是当前价值;bestp是当前最优价值。当cp+r≤bestp时,可剪去右子树。计算右子树中解的上界可以用的方法是将剩余物品依其单位重量价值排序,然后依次装入物品,直至装不下时,再装入该物品的一部分而装满背包。由此得到的价值是右子树中解的上界,用此值来剪枝。 为了便于计算上界,可先将物品依其单位重量价值从大到小排序,此后只要顺序考察各物品即可。在实现时,由MaxBoundary函数计算当前结点处的上界。它是类Knap的私有成员。Knap的其他成员记录了解空间树种的节点信息,以减少函数参数的传递以及递归调用时所需要的栈空间。在解空间树的当前扩展结点处,仅当要进入右子树时才计算上界函数MaxBoundary,以判断是否可以将右子树减去。进入左子树时不需要计算上界,因为其上界与父结点的上界相同。 在调用函数Knapsack之前,需要先将各物品依其单位重量价值从达到小排序。为此目的,我们定义了类Objiect。其中,运算符与通常的定义相反,其目的是为了方便调用已有的排序算法。在通常情况下,排序算法将待排序元素从小到大排序。 在搜索状态空间树时,由函数Backtrack控制。在函数中是利用递归调用的方法实现了空间树的搜索
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

打赏作者

Corleone_1

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

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

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

打赏作者

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

抵扣说明:

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

余额充值