回溯法——求解子集和问题(Java)

这篇具有很好参考价值的文章主要介绍了回溯法——求解子集和问题(Java)。希望对大家有所帮助。如果存在错误或未考虑完全的地方,请大家不吝赐教,您也可以点击"举报违法"按钮提交疑问。

一、问题描述

给定n个不同的正整数的集合w={w1,w2,…,wn}和一个正整数W,要求找出w的子集s,使该子集中所有的元素的和为W。例如,当n=4时,w={11,13,24,7},W=31,则满足要求的子集为(11,13,7)和(24,7)。

二、问题求解

和0/1背包问题一样,该问题的解空间数是一颗子集树。设解向量x=(x1,x2,…,xn),这里是求所有满足条件的解,所有一旦搜索到叶子结点(即全部结点搜索完,即i>n),如果相应的子集和为W,则输出x解向量。
if(i>n) { if(tw==W) { count++; solution(x); } }
当搜索到第i个结点(1<=i<=n)的某点结点时,用tw表示选取的整数和,rw表示余下的整数和。
对于n=4的背包问题,其解空间数如下图所示,树中的16个叶子结点分别代表着16个可能的解。
回溯法——求解子集和问题(Java)
对于以上问题的求解,是非常繁琐的。为了剪去不必要的子树,减少问题求解所需实际生成的状态结点数,我们利用剪枝函数。剪枝函数包括约束函数和限界函数。(解空间数左边是1(选择),右边是0(不选择)!!!
(1)约束函数–剪掉得不到的可行解,避免无谓地搜索。
相当于左剪枝,通过检查当前整数w[i]加入后子集和是否超过W。若超过了则需要剪枝,仅仅扩展满足tw+w[i]<=W的左孩子结点不用剪枝。

 if(tw+w[i]<=W) //不用剪左子树的情况,
            {
                x[i]=1;
                dfs(i+1,tw+w[i],rw-w[i],x);
            }

(2)限界函数–剪掉得不到最优解的子树。
相当于右剪枝,如果一个结点tw+rw-w[i]<W或者tw+rw<=W,也就是说即便选择剩余所有整数,也不可能找到一个解,仅仅扩展满足tw+rw-w[i]>=W或者tw+rw >W的右孩子结点不用剪枝。

对于第二个点补充解释。为啥是tw+rw-w[i]<W或者tw+rw<W,就要剪枝?
我们是求该子集中所有的元素加起来=W。而tw表示选取的整数和,rw表示余下的整数和,w[i]表示当前的重量。如果当前所选取的重量加上剩余的重量仍然W,就不可能找到一个和W相等的值,至于为啥-w[i],我的理解是右边是不选择,就相当于不选择当前的重量,即使减不减也无所谓(如果理解有误请指出)。

 if(tw+rw-w[i]>=W) //不用剪右子树的情况
            {
                x[i]=0;
                dfs(i+1,tw,rw-w[i],x);
            }

剪掉之后,如下图所示:
回溯法——求解子集和问题(Java)

  • 使用剪枝函数的深度优先生成状态空间数结点的求解方法称为回溯法
  • 广度优先生成结点,并使用剪枝函数的方法称为分枝限界法。

三、使用步骤

整体代码

package 算法作业;
//求解子集和问题  所有子集所有元素加起来=W
public class SubsetSum {
     static int n=4;
     static int W=31; //比如有四个背包 最大载重量为31
    static int[]w=new int[100];
    static int[] x=new int[100];
    //static int[] w ={11,13,24,7}; //存放所有整数,不用下标0的元素,比如每一个背包对应的重量
     static int count=0;//累积解的个数
    //tw为考虑第i个元素时前面已经选取的整数(重量)的和,rw就是剩下的整数(重量)的和 x[]看你选不选,选的话就为1,不选就为0
    public static void dfs(int i, int tw, int rw, int x[]){
        if(i>n)  //找完所有的整数
        {
            if(tw==W) //找到一个满足条件的解,就输出它
            {
                count++;
               solution(x);
            }
        }
        else //未找完所有整数
        {
            if(tw+w[i]<=W) //不用剪左子树的情况,
            {
                x[i]=1;
                dfs(i+1,tw+w[i],rw-w[i],x);
            }
            if(tw+rw-w[i]>=W) //不用剪右子树的情况
            {
                x[i]=0;
                dfs(i+1,tw,rw-w[i],x);
            }
        }
    }

    public static void solution(int x[]) {
        System.out.println("第"+count+"个解:");
        System.out.println("选取的数为:");
        for(int i=1;i<=n;i++){
            if(x[i]==1){
                System.out.println(w[i]);
            }
        }
    }
    public static void main(String[] args){
        w[1]=7;
        w[2]=11;
        w[3]=13;
        w[4]=24;
        int rw=0;
        for(int j=1;j<=n;j++){
            rw+=w[j];
        }
        dfs(1,0,rw,x);
    }
}

实验结果:
回溯法——求解子集和问题(Java)文章来源地址https://www.toymoban.com/news/detail-460660.html

到了这里,关于回溯法——求解子集和问题(Java)的文章就介绍完了。如果您还想了解更多内容,请在右上角搜索TOY模板网以前的文章或继续浏览下面的相关文章,希望大家以后多多支持TOY模板网!

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处: 如若内容造成侵权/违法违规/事实不符,请点击违法举报进行投诉反馈,一经查实,立即删除!

领支付宝红包 赞助服务器费用

相关文章

  • 代码随想录-回溯算法(子集问题)|ACM模式

    目录 前言: 78. 子集 题目描述: 输入输出描述: 思路和想法: 90. 子集 II 题目描述: 输入输出描述: 思路和想法: 491. 递增子序列 题目描述: 输入输出描述: 思路和想法: 如果把 子集问题、组合问题、分割问题都抽象为一棵树的话, 那么组合问题和分割问题都是收集

    2024年02月15日
    浏览(156)
  • (3)回溯算法团灭子集、组合、排列问题 -- 元素无重可复选

    回溯算法团灭子集、组合、排列问题 根据元素是否重复和是否可复选,分为以下三种变体: 1、元素无重不可复选 2、元素有重不可复选 3、元素无重可复选 该篇给出第三种情况的代码,另外两种的实现见上方变体链接。

    2024年02月09日
    浏览(32)
  • 回溯法求解八皇后问题

    问题提出 :八皇后问题是一个古老而著名的问题。该问题是十九世纪著名的数学家高斯1850 提出在 8x8 格的国际象棋上摆放八皇后,使其不能互相攻击,即任意两个皇后都不能处于同一行、同一列或同一斜线上,问有多少种摆法。高斯认为有76种方案。1854年在柏林的象棋杂志

    2023年04月08日
    浏览(58)
  • 基于回溯法求解0-1背包问题

    一、实验目的 1.掌握基于回溯的算法求解0-1背包问题的原理。 2.掌握编写回溯法求解0-1背包问题函数的具体步骤并理解回溯法的核心思想以及其求解过程。 3.掌握子集树以及其他几种解空间树的回溯方法并具备运用回溯算法的思想设计算法并用于求解其他实际应用问题的能力

    2024年02月08日
    浏览(46)
  • 基于回溯法求解旅行售货员问题

    一、实验目的 1.掌握基于回溯的算法求解旅行商问题的原理。 2.掌握编写回溯法求解旅行商问题函数的具体步骤并理解回溯法的核心思想以及其求解过程。 3.掌握子集树以及其他几种解空间树的回溯方法并具备运用回溯算法的思想设计算法并用于求解其他实际应用问题的能力

    2024年02月09日
    浏览(41)
  • 回溯法,分支限界法,动态规划法求解0-1背包问题(c++)

    问题描述 给定n种物品和一背包。物品i的重量是wi0,其价值为vi0,背包的容量为c。问应如何选择装入背包中的物品,使得装入背包中物品的总价值最大? 搜索空间: 子集树(完全二叉树) 约束函数(进包用): 如果当前背包中的物品总重量是cw,前面k-1件物品都已经决定是否进包,那

    2024年02月10日
    浏览(58)
  • 【算法设计与分析】拉丁矩阵问题——对于给定的m和n,计算出不同的宝石排列方案数。

    问题描述   现有n种不同形状的宝石,每种宝石有足够多颗。欲将这些宝石排列成m行n列的一个矩阵,m≤n,使矩阵中每行和每列的宝石都没有相同的形状。试设计一个算法,计算出对于给定的m和n,有多少种不同的宝石排列方案。 数据输入   由文件input.txt给出输入数据。

    2024年02月04日
    浏览(41)
  • 子集-回溯方法

    2024年02月12日
    浏览(37)
  • 【力扣】416. 分割等和子集 <动态规划、回溯>

    给你一个 只包含正整数的非空数组 nums 。请你判断是否可以将这个数组分割成两个子集,使得两个子集的元素和相等。 示例 1: 输入:nums = [1,5,11,5] 输出:true 解释:数组可以分割成 [1, 5, 5] 和 [11] 。 示例 2: 输入:nums = [1,2,3,5] 输出:false 解释:数组不能分割成两个元素和

    2024年02月10日
    浏览(40)
  • 【数据结构】回溯算法公式化解题 leetcode经典题目带刷:全排列、组合、子集

    一、什么是回溯算法 回溯算法(Backtracking Algorithm)是一种解决 组合问题 、 排列问题 、 选择问题 等一类问题的常用算法。它通过尝试所有可能的选择来找到问题的解,当发现当前选择不符合要求时,就回溯到之前的状态,然后尝试其他的选择。 1、基本思想: 从问题的起

    2024年02月11日
    浏览(45)

觉得文章有用就打赏一下文章作者

支付宝扫一扫打赏

博客赞助

微信扫一扫打赏

请作者喝杯咖啡吧~博客赞助

支付宝扫一扫领取红包,优惠每天领

二维码1

领取红包

二维码2

领红包