目录

1 问题描述

2 解决方案

2.1 全排列思想求解

2.2 状态空间树思想求解

 


1 问题描述

求n个正整数构成的一个给定集合A = {a1,a2,a3,...,an}的子集,子集的和要等于一个给定的正整数d。请输出所有符合条件的子集。


2 解决方案

本文下面编码思想参考自文末参考资料,下面的思想讲解直接引用文末参考资料1。

2.1 全排列思想求解

方法1:首先,将子集保存在一个数组链表中,每次往链表中添加一个元素;
从空集增加到最大集,再回溯,递归返回的时候,再将链表最后一个元素从子集移出;
这样就实现了,元素在与不在子集中,这两种状态。
注意,每次加入一个元素得到的,子集数组中的元素就构成了一个子集。

具体代码如下:

package com.liuzhen.chapter12;

import java.util.ArrayList;

public class SubSet {

    public ArrayList<Integer> list = new ArrayList<Integer>();   //用于存放求取子集中的元素
//求取数组链表中元素和
public int getSum(ArrayList<Integer> list) {
int sum = 0;
for(int i = 0;i < list.size();i++)
sum += list.get(i);
return sum;
}
/*
* 参数step:选中数组A中第step个元素为子集元素
* 函数功能:求取数组A中一个子集元素,其相加之和等于m
*/
public void getSubSet(int[] A, int m, int step) {
while(step < A.length) {
list.add(A[step]); //递归执行语句,向数组链表中添加一个元素
if(getSum(list) == m) //链表中元素和等于m
System.out.println(list);
step++;
getSubSet(A, m, step);
list.remove(list.size() - 1); //回溯执行语句,删除数组链表最后一个元素
}
} public static void main(String[] args) {
SubSet test = new SubSet();
int[] A = new int[6];
for(int i = 0;i < 6;i++) {
A[i] = i + 1;
}
test.getSubSet(A, 8, 0);
}

运行结果:

[1, 2, 5]
[1, 3, 4]
[2, 6]
[3, 5]

2.2 状态空间树思想求解

方法2:从元素在与不在子集这两种状态来考虑,因为每个元素都有两种状态,
可以理解为一种二叉树的形式,如下图:

每一个元素带有一个属性,在不在子集中,1(true)表示在子集,0(false)表示不再自己中。
每个元素的状态初始化为1,实际上无需去构造二叉树。
第一个递归将所有元素逐个放入子集,当所有元素放入子集后回溯。
第一次递归返回后,将最后一个元素移出子集,这样每个元素在与不在子集的状态都可以遍历到,每次遍历到最后一个元素时,按照元素的状态打印字符序列,得到的就是一个子集。

具体代码如下:

package com.liuzhen.chapter12;

import java.util.ArrayList;

public class SubSet {

    public int getSum1(boolean[] visited, int[] A) {
int sum = 0;
for(int i = 0;i < A.length;i++) {
if(visited[i])
sum += A[i];
}
return sum;
} public void getSubSet1(boolean[] visited, int[] A, int m, int step) {
if(step == A.length) {
if(getSum1(visited, A) == m) {
for(int i = 0;i < A.length;i++) {
if(visited[i])
System.out.print(A[i]+" ");
}
System.out.println();
}
return;
}
visited[step] = true;
getSubSet1(visited, A, m, step + 1);
visited[step] = false;
getSubSet1(visited, A, m, step + 1);
} public static void main(String[] args) {
SubSet test = new SubSet();
int[] A = new int[6];
boolean[] visited = new boolean[6];
for(int i = 0;i < 6;i++) {
A[i] = i + 1;
visited[i] = false;
}
test.getSubSet1(visited, A, 8, 0);
}
}

运行结果:

1 2 5
1 3 4
2 6
3 5

参考资料:

1. Algorithm:求集合子集的几种思路和方法(2)回溯法

算法笔记_074:子集和问题(Java)的更多相关文章

  1. 算法笔记_023:拓扑排序(Java)

    目录 1 问题描述 2 解决方案 2.1 基于减治法实现 2.2 基于深度优先查找实现 1 问题描述 给定一个有向图,求取此图的拓扑排序序列. 那么,何为拓扑排序? 定义:将有向图中的顶点以线性方式进 ...

  2. 算法笔记_137:二分图的最大匹配(Java)

    目录 1 问题描述 2 解决方案   1 问题描述 何为二分图的最大匹配问题? 引用自百度百科: 首先得说明一下何为匹配: 给定一个二分图G,在G的一个子图M中,M的边集{E}中的任意两条边都不依附于 ...

  3. 算法笔记_228:信用卡号校验(Java)

    目录 1 问题描述 2 解决方案   1 问题描述 当你输入信用卡号码的时候,有没有担心输错了而造成损失呢?其实可以不必这么担心,因为并不是一个随便的信用卡号码都是合法的,它必须通过Luhn算法来验证 ...

  4. 算法笔记_138:稳定婚姻问题(Java)

    目录 1 问题描述 2 解决方案   1 问题描述 何为稳定婚姻问题? 有一个男士的集合Y = {m1,m2,m3...,mn}和一个女士的计划X = {n1,n2,n3,...,nn}.每一个男士有 ...

  5. 算法笔记_132:最大流量问题(Java)

    目录 1 问题描述 2 解决方案   1 问题描述 何为最大流量问题? 给定一个有向图,并为每一个顶点设定编号为0~n,现在求取从顶点0(PS:也可以称为源点)到顶点n(PS:也可以称为汇点)后,顶点 ...

  6. 算法笔记_040:二进制幂(Java)

    目录 1 问题描述 2 解决方案 2.1 从左至右二进制幂 2.2 从右至左二进制幂   1 问题描述 使用n的二进制表示,计算a的n次方. 2 解决方案 2.1 从左至右二进制幂 此方法计算a的n次 ...

  7. 算法笔记_014:合并排序(Java)

    1 问题描述 给定一组数据,使用合并排序得到这组数据的非降序排列. 2 解决方案 2.1 合并排序原理简介 引用自百度百科: 合并排序是建立在归并操作上的一种有效的排序算法.该算法是采用分治法(Div ...

  8. 算法笔记_233:二阶魔方旋转(Java)

    目录 1 问题描述 2 解决方案   1 问题描述 魔方可以对它的6个面自由旋转. 我们来操作一个2阶魔方(如图1所示): 为了描述方便,我们为它建立了坐标系. 各个面的初始状态如下:x轴正向:绿x轴 ...

  9. 算法笔记_227:填写乘法算式(Java)

    目录 1 问题描述 2 解决方案   1 问题描述 观察下面的算式: * * × * * = * * * 它表示:两个两位数字相乘,结果是3位数.其中的星号(*)代表任意的数字,可以相同,也可以不同, ...

随机推荐

  1. 贪心【CF1029E】Tree with Small Distances

    Description 给定一棵树.要求往树中加入一些边使得从1到其他节点的距离至多是2 . 输出加入边的最小数量.(边全部都是无向的) Input 第一行一个整数n,表示树中的节点个数. 接下来n− ...

  2. Linux命令之whereis

    whereis [选项] [文件] (1).选项 -b 只搜索二进制文件 -B <目录> 只在路径下查找二进制文件 -m 只搜索man手册 -M <目录> 只在路径下查找man ...

  3. Python - 字符和字符值之间的转换

    字符和字符值之间的转换 Python中, 字符和字符值, 直接的转换, 包含ASCII码和字母之间的转换,Unicode码和数字之间的转换; 也可以使用map, 进行批量转换, 输出为集合, 使用jo ...

  4. BZOJ 3391 [Usaco2004 Dec]Tree Cutting网络破坏(树形DP)

    [题目链接] http://www.lydsy.com/JudgeOnline/problem.php?id=3391 [题目大意] 给定一棵树,求分支size均不大于一半点数的点 [题解] 递归的同 ...

  5. 【数位dp】UVA - 11361 - Investigating Div-Sum Property

    经典数位dp!而且这好像是数位dp的套路板子……不需要讨论原来我很头疼的一些边界. 改天用这个板子重做一下原来的一些数位dp题目. http://blog.csdn.net/the_useless/a ...

  6. linux 配置信息

    # uname -a # 查看内核/操作系统/CPU信息 # head -n 1 /etc/issue # 查看操作系统版本 # cat /proc/cpuinfo # 查看CPU信息 # hostn ...

  7. 关于abstract class 和 interface

    1.abstract class 在 Java 语言中表示的是一种继承关系,一个类只能使用一次继承关系.但是,一个类却可以实现多个interface. 2.在abstract class 中可以有自己 ...

  8. Android应用程序的解析

    一: 文件架构 二: 图片,语音资源的使用 图片的两种使用方法: 第一种: 使用imageView控件 <ImageView android:id="@+id/imageView1&q ...

  9. .net 中两个日期算经过的月份数

    DateTime startDate = DateTime.Parse("2014-11-1"); DateTime endDate = DateTime.Parse(" ...

  10. bash中的快捷键使用

    移动 ctrl + xx              光标在行首.位移动 ctrl + 方向左键      光标移动到前一个单词的开始 ctrl + 方向右键      光标移动到后一个单词的开始   ...