【运筹优化】子集和问题(Subset Sum Problems , SSP)介绍 + 动态规划求解 + Java代码实现

这篇具有很好参考价值的文章主要介绍了【运筹优化】子集和问题(Subset Sum Problems , SSP)介绍 + 动态规划求解 + Java代码实现。希望对大家有所帮助。如果存在错误或未考虑完全的地方,请大家不吝赐教,您也可以点击"举报违法"按钮提交疑问。


一、问题介绍

子集和问题(Subset Sum Problems , SSP),它是复杂性理论中最重要的问题之一。

SSP会给定一组整数 a 1 , a 2 , . . . . , a n a_1,a_2,....,a_n a1,a2,....,an ,最多 n n n 个整数,我们需要判断是否存在一个非空子集,使得子集的总和为 M M M 整数?如果存在则需要输出该子集。

例如,集合给定为 [ 5 , 2 , 1 , 3 , 9 ] [5,2,1,3,9] [5,2,1,3,9] ,子集之和为 9 9 9 ;答案是肯定的,因为子集 [ 5 , 3 , 1 ] [5,3,1] [5,3,1] 的总和等于 9 9 9

这是一个 N P NP NP 完全问题。是背包的特殊情况。

为子集和问题设计一个动态规划算法,# 运筹优化,人工智能,动态规划,java,算法,SSP,子集和问题

目的: 给定一组正整数和一个值 S 总和,找出数组中是否存在一个子集,其总和等于给定的总和 S。


二、动态规划求解思路

设 A 是包含“n”个非负整数的数组或集合。找到集合“A”的子集“x”,使得 x 的所有元素的总和等于 w,其中 x 是另一个输入(总和)。

例如:

A = [2, 3, 5, 7, 10]

总和 (w) = 14

首先,我们创建一个表。该列包含从 0 到 14 的值,而行包含给定集合的元素,如下所示:

在下表中:

i :它表示行。行表示元素。

j :它表示列。列表示总和。

为子集和问题设计一个动态规划算法,# 运筹优化,人工智能,动态规划,java,算法,SSP,子集和问题
我们将使用 1 作为真值,使用 0 作为假值。值 1 位于 0 和 2 列下,如下所示:

这里 i=1, a[i] =2

注:每列的填充规则如下:
所需总和 = j - 元素
A[i][j] = A[i-1][所需总和]

当 j = 1

所需总和 = 1 - 2 = -1;由于总和为负,因此如上表所示,在第 1 列下输入 0。

当 j = 2

所需总和 = 2 - 2 = 0;由于 sum 的值为零,因此我们将 1 放在第 2 列下,如上表所示。

我们将 0 放在总和大于 2 的列下,因为我们不能从元素 2 中得出总和超过 2。

考虑要素 3。

这里 i = 2, a[i] = 3

为子集和问题设计一个动态规划算法,# 运筹优化,人工智能,动态规划,java,算法,SSP,子集和问题
总和小于 3 的列将具有与前几列相同的值。

当 j = 3 时,总和 [j] = 3

所需总和 = 3 -3 = 0;由于总和为零,因此我们将 1 放在第 3 列下,如上表所示。

当 j = 4;总和[j] = 4

所需总和 = 4 - 3 = 1;由于总和为 1,因此我们移至前一行,即 i=1 和 j=1。a[1][1] 处的值为 0,因此我们将 0 放在 a[2][4] 处。

当 j = 5 时,总和 [j] = 5

所需总和 = 5 -3 = 2;sum 的值为 2,因此 a[1][2] 处的值等于 1。因此,a[2][5] 处的值将为 1。

当 j = 6 时,总和 [j] = 6

所需总和 = 6 -3 = 3;sum 的值为 3,因此 a[1][3] 处的值等于 0。因此,a[2][6] 处的值将为 0。

当 j = 7 时,总和 [7] = 7

所需总和 = 7 - 3 = 4;sum 的值为 4,因此 a[1][4] 处的值等于 0。因此,a[2][7] 处的值将为 0。

这样,我们从第 8 列到 14 列中获取值 0。

考虑要素 5。

这里 i=3, a[i] = 5

为子集和问题设计一个动态规划算法,# 运筹优化,人工智能,动态规划,java,算法,SSP,子集和问题
总和小于 5 的列将具有与前几列相同的值。

当 j = 5 时,总和 [j] = 5

所需总和 = 5-5 = 0;由于总和的值为 0;因此,A[2][5] 处的值等于 1。

当 j = 6 时,总和 [j] = 6

所需总和 = 6-5 = 1;sum 的值为 1,因此 a[2][1] 处的值等于 0;因此,a[3][6] 处的值等于 0。

当 j=7 时,总和 [j] = 7

所需总和 = 7-5 = 2;sum 的值为 2,因此 a[2][2] 处的值等于 1;因此,a[3][7] 处的值等于 1。

当 j=8 时,总和 [j] = 8

所需总和 = 8-5 = 3;sum 的值为 3,因此 a[2][3] 处的值等于 1;因此,a[3][8] 处的值等于 1。

当 j=9 时,总和 [j] =9

所需总和 = 9-5 = 4;sum 的值为 4,因此 a[2][4] 处的值等于 0;因此,a[3][9] 处的值等于 0。

这样,我们从第 10 列到 14 列中获取值。

考虑要素 7。

这里 i=4, a[i] =7

为子集和问题设计一个动态规划算法,# 运筹优化,人工智能,动态规划,java,算法,SSP,子集和问题
总和小于 7 的列将具有与前几列相同的值。

当 j=9 时,总和 [j] = 9

所需总和 = 9 - 7 = 2;sum 的值为 2,因此 a[3][2] 处的值等于 1;因此,a[4][9] 处的值等于 1。

当 j=10 时,总和 [j] = 10

所需总和 = 10 - 7= 3;sum 的值为 3,因此 a[3][3] 处的值等于 1;因此,a[4][10] 处的值等于 1。

当 j=11 时,总和 [j] =11

所需总和 = 11-7 = 4;sum 的值为 4,因此 a[3][4] 处的值等于 0;因此,a[4][11] 处的值等于 0。

当 j=12 时,总和 [j] = 12

所需总和 = 12-7 = 5;sum 的值为 5,因此 a[3][5] 处的值等于 1;因此,a[4][12] 处的值等于 1。

当 j=13 时,总和 [j] =13

所需总和 = 13 - 7 = 6;sum 的值为 6,因此 a[3][6] 处的值等于 0;因此,a[4][13] 处的值等于 0。

当 j=14 时,总和 [j] = 14

所需总和 = 14 - 7 = 7;sum 的值为 7,因此 a[3][7] 处的值等于 1;因此,a[4][14] 处的值等于 1。

考虑元素 10

这里 i=5, a[i] = 10

为子集和问题设计一个动态规划算法,# 运筹优化,人工智能,动态规划,java,算法,SSP,子集和问题

总和小于 10 的列将具有与前几列相同的值。

当 j = 10 时,总和 [j] = 10

所需总和 = 10 - 10 = 0;sum 的值为 0,因此 a[4][0] 处的值等于 1;因此,a[5][10] 处的值等于 1。

当 j = 11 时,总和 [j] = 11

所需总和 = 11 - 10 = 1;总和的值为 1,因此 a[4][1] 处的值等于 0;因此,a[5][11] 处的值等于 0。

当 j=12 时,总和 [j] = 12

所需总和 = 12-10 = 2;sum 的值为 2,因此 a[4][2] 处的值等于 1;因此,A[5][12] 处的值等于 1。

当 j=13 时,总和 [j] = 13

所需总和 = 13 - 10 = 3;sum 的值为 3,因此 a[4][3] 处的值等于 1;因此,a[5][13] 处的值等于 1。

为了确定上述给定的问题是否包含子集,我们需要检查最后一行和最后一列。如果值为 1,则表示至少存在一个子集。

我们基本上遵循三个条件,在表的单元格中写入 1:
• A[i] = j
• A[i-1][j] = 1
• A[i-1][j-A[i]] = 1


三、Java代码实现

测试案例

A = {2, 3, 5, 7, 10}
sum = 14

Java代码

import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;

/**
 * @Author:WSKH
 * @ClassName:SSP_DP
 * @ClassType:
 * @Description:
 * @Date:2022/12/18/18:42
 * @Email:1187560563@qq.com
 * @Blog:https://blog.csdn.net/weixin_51545953?type=blog
 */
public class SSP_DP {

    public static void main(String[] args) {
        int sum = 14;
        int[] arr = new int[]{2, 3, 5, 7, 10};
        long s = System.currentTimeMillis();
        new SSP_DP().solve(arr, sum);
        System.out.println("用时: " + (System.currentTimeMillis() - s) / 1000d + " s");
    }

    static int totalWei = 32;
    
    static int arrLength;

    public void solve(int[] arr, int sum) {
        // 如果sum=0直接返回空集
        if (sum == 0) {
            System.out.println(new ArrayList<>());
            return;
        }
        // 深拷贝数组
        arr = arr.clone();
        // 升序排序数组
        Arrays.sort(arr);
        SubSolution[] dp = new SubSolution[sum + 1];
        arrLength = arr.length;
        for (int rowIndex = 0; rowIndex < arr.length; rowIndex++) {
            if (arr[rowIndex] > sum) {
                break;
            }
            // 遍历上一层除了0位置外,有1的位置
            if (rowIndex > 0) {
                for (int colIndex = sum - arr[rowIndex]; colIndex >= 1; colIndex--) {
                    if (dp[colIndex] != null) {
                        if (dp[colIndex + arr[rowIndex]] == null) {
                            dp[colIndex + arr[rowIndex]] = new SubSolution(dp[colIndex].flag, rowIndex);
                        }
                    }
                }
            }
            // 将刚好等于的位置赋值
            if (dp[arr[rowIndex]] == null) {
                dp[arr[rowIndex]] = new SubSolution(rowIndex);
            }
            for (SubSolution subSolution : dp) {
                System.out.print((subSolution == null ? 0 : 1) + ",");
            }
            System.out.println();
        }
        if (dp[sum] != null) {
            int checkSum = 0;
            List<Integer> valueList = new ArrayList<>();
            for (int i = 0; i < arr.length; i++) {
                if ((dp[sum].flag[i / totalWei] & (1 << (i % totalWei))) != 0) {
                    valueList.add(arr[i]);
                    checkSum += arr[i];
                }
            }
            if (checkSum != sum) {
                throw new RuntimeException(valueList + " 的和不等于 " + sum);
            }
            System.out.println(valueList);
        } else {
            System.out.println(Arrays.toString(arr) + "中,没有和为" + sum + "的子集");
        }
    }

    public static class SubSolution {
        int[] flag;

        public SubSolution() {
            flag = new int[arrLength / totalWei + 1];
        }

        public SubSolution(int index) {
            flag = new int[arrLength / totalWei + 1];
            flag[index / totalWei] = (flag[index / totalWei] | (1 << index % totalWei));
        }

        public SubSolution(int[] flag, int index) {
            this.flag = flag.clone();
            this.flag[index / totalWei] = (this.flag[index / totalWei] | (1 << index % totalWei));
        }

    }

}

输出文章来源地址https://www.toymoban.com/news/detail-796184.html

0,0,1,0,0,0,0,0,0,0,0,0,0,0,0,
0,0,1,1,0,1,0,0,0,0,0,0,0,0,0,
0,0,1,1,0,1,0,1,1,0,1,0,0,0,0,
0,0,1,1,0,1,0,1,1,1,1,0,1,0,1,
0,0,1,1,0,1,0,1,1,1,1,0,1,1,1,
[2, 5, 7]
用时: 0.002 s

到了这里,关于【运筹优化】子集和问题(Subset Sum Problems , SSP)介绍 + 动态规划求解 + Java代码实现的文章就介绍完了。如果您还想了解更多内容,请在右上角搜索TOY模板网以前的文章或继续浏览下面的相关文章,希望大家以后多多支持TOY模板网!

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

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

相关文章

  • 【运筹优化】带时间窗约束的车辆路径规划问题(VRPTW)详解 + Python 调用 Gurobi 建模求解

    车辆路径规划问题(Vehicle Routing Problem,VRP)一般指的是:对一系列发货点和收货点,组织调用一定的车辆,安排适当的行车路线,使车辆有序地通过它们,在满足指定的约束条件下(例如:货物的需求量与发货量,交发货时间,车辆容量限制,行驶里程限制,行驶时间限制等)

    2024年02月02日
    浏览(33)
  • 安装ROS Noetic 出现这样的问题: E: Unable to correct problems, you have held broken packages 解决方法及介绍

    如果在尝试安装ROS Noetic时遇到了“E: Unable to correct problems, you have held broken packages”的错误,这通常意味着您的系统上存在依赖关系问题。这可能是由于缺失的软件包、不兼容的库版本或者软件源问题导致的。尝试以下方法来解决此问题 使用apt命令检查依赖关系问题。例如,

    2024年02月07日
    浏览(35)
  • 分布式鲁棒优化基础知识学习 | Ref:《鲁棒优化入门》「运筹OR帷幄」

    鲁棒:考虑最坏情况; 分布:最坏情况的主体是环境参数的分布变量。 从数学角度说,分布式鲁棒优化囊括随机规划和传统鲁棒优化两种形式。 当分布式鲁棒优化下,环境变量的分布函数获知时,分布鲁棒优化退化为随机优化;仅知其不确定集时,退化为经典鲁棒优化。

    2024年02月08日
    浏览(35)
  • 软件工具 | Python调用运筹优化求解器(一):以CVRP&VRPTW为例

    欢迎关注个人微信公众号:Python助力交通 优化求解器是解决复杂工程问题不可或缺的工具,可以帮助我们验证模型的正确性、理解决策变量的耦合关系、获取最优决策方案(合适规模条件下)。小编搜罗了网上关于各类常见(其实并不常见)的优化求解器介绍的帖子: 优化

    2024年02月10日
    浏览(39)
  • 运筹学经典问题(五):多商品流运输问题

    前面介绍了多商品网络流(MCNF)问题,今天要介绍的多商品流运输问题(Mulit-commodity Transportation Problem, MCTP)与MCNF的唯一差异别:MCTP要求商品直接从供应商运送到客户,没有中间流转的路径。 集合: S S S :供应商的集合; C C C :客户的集合; A A A :网络中弧段的集合,

    2024年02月04日
    浏览(39)
  • 运筹说 第76期 | 最短路问题

    通过前面的学习,我们已经学会了图与网络问题中图的基本概念和最小树问题,本期小编带大家学习 最短路问题。 一 最短路问题 最短路问题是网络理论中应用最广泛的问题之一。许多优化问题可以使用这个模型,如设备更新、管道敷设、线路安排、厂区布局等。 最短路问

    2024年02月12日
    浏览(23)
  • 运筹说 第80期 | 最小费用最大流问题

    前面我们学习了图与网络分析的基础知识及经典问题,大家是否已经学会了呢?接下来小编和大家学习最后一个经典问题—— 最小费用最大流问题 。 最小费用最大流问题是经济学和管理学中的一类典型问题。在一个网络中每段路径都有“容量”和“费用”两个限制的条件下

    2024年01月16日
    浏览(34)
  • 运筹系列82:使用动态规划求解TSP问题

    定义 c ( s , k ) c(s,k) c ( s , k ) 为当前在 k k k ,待访问点的集合 s s s ,最后返回城市0的最短路径,那么Bellman方程为: c ( s , k ) = min ⁡ i ∈ s { c ( s − { i } , i ) + d i , k } c(s,k)=min_{i in s}{c(s-{i},i)+d_{i,k}} c ( s , k ) = min i ∈ s ​ { c ( s − { i } , i ) + d i , k ​ } 为了使用方便,这里

    2024年02月06日
    浏览(34)
  • 运筹学—运输问题与表上作业法

    不考虑运价,从西北角的格子开始分配运量,按尽可能满足一方取小的原则,第一行和第一列的格子分配完后,依次向东南角方向的格子进行运量分配。 例如: 第一步:列出产售平衡表 第二步:利用西北角法进行运量分配: 首先在产售平衡表的x 11 处尽可能取最小值:min

    2024年02月12日
    浏览(34)
  • 运筹系列87:julia求解随机动态规划问题入门

    随机动态规划问题的特点是: 有多个阶段,每个阶段的随机性互不相关,且有有限个实现值 (finite realizations) 具有马尔可夫性质,即每个阶段只受上一个阶段影响,可以用状态转移方程来描述阶段与阶段之间的变化过程。 我们使用julia的SDDP算法包来求解随机动态规划问题。

    2024年01月16日
    浏览(31)

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

支付宝扫一扫打赏

博客赞助

微信扫一扫打赏

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

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

二维码1

领取红包

二维码2

领红包