java-回溯算法子集树概念及解决01背包问题

回溯算法:
回溯算法是对搜索树的一种深度优先搜索。
像大多数NP难问题一样,通过穷尽搜索数量巨大但有限多个可能性,可以获得一个解。而且,事实上对于所有这些问题都不存在用穷尽搜索之外的方法来解决问题。所以产生了开发系统化的搜索技术的需要,并且希望能够将搜索空间减少到尽可能小。
回溯法就是一种组织搜索的一般技术。回溯法可以被描述为有组织的穷举搜索,它常常可以避免搜索所有的可能性。
一般适用于求解那些有潜在的大量解,但有限个数的解已经检查过的问题。
子集树:
当所给问题是从n个元素的集合S中找出S满足某种性质的子集时,相应的解空间称为子集树。
其中01背包的经典问题就可以用子集树来解决。
01背包是在M件物品取出若干件放在空间为W的背包里,每件物品的体积为W1,W2至Wn,与之相对应的价值为P1,P2至Pn。
思路:使用回溯算法求解01背包最优解时需要建立二叉树,树有业务意义的深度为物品数量n,加上根节点总深度为n+1,除了终端节点外,每个叶子节点都有左右两个children节点,left children定义为装入当前物品的情况,right children为不装入当前物品的情况,节点拥有“剩余最大容量”和“当前价值”两个属性,回溯点就是当剩余最大容量无法装入当前物品,或当前物品已是终端节点。
在这里插入图片描述
代码实现:
static int[] w = {5,8,7,9,6};
static int[] v = {12,9,13,10,11};
static int c = 18;

static int[] x = new int[w.length];
static int[] bestx = new int[w.length];
static int cw = 0; // 已选择物品的重量
static int cv = 0; // 已选择物品的价值
static int bestv = Integer.MIN_VALUE; // 物品的最优价值
static int r = 0; //

public static void main(String[] args) {
    for (int i = 0; i < v.length; i++) {
        r += v[i];
    }
    backstrace(0);
    System.out.println("bestv:" + bestv);
    System.out.println(Arrays.toString(bestx));
}

private static void backstrace(int i) {
    if(i == w.length){
        if(cv > bestv){
            bestv = cv; // 更新最优价值
            for (int j = 0; j < x.length; j++) {
                bestx[j] = x[j]; // 更新最优价值选择的物品的子集
            }
        }
    } else {
        r -= v[i];
        if(cw + w[i] <= c){
            cv += v[i];
            cw += w[i];
            x[i] = 1;
            backstrace(i+1);  // i节点的左孩子
            cw -= w[i];
            cv -= v[i];
        }

        // 当前已选择物品的总价值
        if(cv + r > bestv){   // r此时不包含物品i的价值
            x[i] = 0;
            backstrace(i+1); // i节点的右孩子
        }

        r += v[i];
    }
}

运行结果:
在这里插入图片描述

  • 0
    点赞
  • 3
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值