继续讲故事~~
  上次讲到我们的主人公丁丁,用神奇的动态规划法解决了杂货店老板的两个找零钱问题,得到了老板的肯定。之后,他就决心去大城市闯荡了,看一看外面更大的世界。
  这天,丁丁刚回到家,他的弟弟小连就拦住了他,“老哥,有个问题想请教你。”对于一向数学见长的小连,这次竟然破天荒的来问自己问题,丁丁感到不可思议:他俩一个以计算机见长,一个以数学见长,各自心里都有点小骄傲,不会轻易地向对方问问题。丁丁迟疑了一会儿,慢慢说道:“有什么问题是我们数学小天才解决不了的?”
  原来小连刚上高一,正在学数学中的集合,这不,今天他从一本算法书上看到一道题,想了很久都没有想出来。他把题目给了丁丁看:

对于某个给定值M,如何从某个给定的正整数集合S中找个一个子集合s,使得该子集和为给定值M。如M=7,S={1,3,4,5},则s={3,4}.

  看到这道题目,丁丁脑海中掠过“动态规划法”的念头,对于动态规划法,他已经是轻车熟路了,但是对于究竟能否用动态规划法解决这个问题,他一时也没主意。于是,他对小连说道:“这题也许可以用动态规划法解决,不过我得好好想一想。”小连点点头,他还是蛮相信他的哥哥的。
  丁丁走进自己的房间,拿出草稿纸,开始了思考的旅程:

对于 S={a1,a2,...,an} S = { a 1 , a 2 , . . . , a n } S=\{a_{1},a_{2},...,a_{n}\},每个元素只有取与不取两种情况,再考虑它们的和是否等于M,但是这样的情况共有 2n 2 n 2^{n}中,这种算法的效率显然是不行的。

  换条思路,令subset(i,j)表示S中前i个元素的子集和等于j的情况,则

  • 若S[i] > j,则S[i]不在子集s中。
  • 若S[i] <= j, 则有以下两种情况:一种情况是S[i]不在子集s中,则subset(i, j) = subset(i-1, j); 一种情况是S[i]在子集s中,则subset(i, j)= subset(i-1, j-S[i]).

  这样就有了这个问题的子结构问题,因此,只需要确定初始情况即可:

对于i=0,1,2,…,n,有subset(i, 0)=True, 对于j=1,2,…,M, 有subset(0, j)=False.

因此,利用动态规划法,就能得到(n+1)*(M+1)的真值表了,而答案就是subset(n, M). 算法有了,Python代码自然也有了:

import numpy as np# A Dynamic Programming solution for subset sum problem
# Returns true if there is a subset of set with sum equal to given sumdef isSubsetSum(S, n, M):# The value of subset[i, j] will be# true if there is a subset of# set[0..j-1] with sum equal to isubset = np.array([[True]*(M+1)]*(n+1))# If sum is 0, then answer is truefor i in range(0, n+1):subset[i, 0] = True# If sum is not 0 and set is empty,# then answer is falsefor i in range(1, M+1):subset[0, i] = False# Fill the subset table in bottom-up mannerfor i in range(1, n+1):for j in range(1, M+1):if j < S[i-1]:subset[i, j] = subset[i-1, j]else:subset[i, j] = subset[i-1, j] or subset[i-1, j-S[i-1]]# print the True-False tablefor i in range(0, n+1):for j in range(0, M+1):print('%-6s'%subset[i][j], end="  ")print(" ")if subset[n, M]:print("Found a subset with given sum")else:print("No subset with given sum")# test
st = [1, 3, 4, 5]
n = len(st)
sm = 7
isSubsetSum(st, n, sm)

输出结果如下:

True    False   False   False   False   False   False   False
True    True    False   False   False   False   False   False
True    True    False   True    True    False   False   False
True    True    False   True    True    True    False   True
True    True    False   True    True    True    True    True
Found a subset with given sum

  那么,怎样求解子集s中的元素呢?也许可以用回溯法(backtracing),他这样想到,不过,他还是决定把剩余部分交给弟弟小连。
  几分钟后,当小连看到丁丁的解法后,兴奋地直跳起来。对于计算机编程,他也是有相当大的兴趣的,不过当务之急是解决哥哥剩下来的问题,那就是找出s中的元素。他想试着从输出的真值表入手:

对于subset(i, j) = subset(i-1, j)=True,则元素S[i]不在子集s中。对于subset(i,j)=True而subset(i-1, j)=False,则元素S[i]必定在子集s中, 此时subset(i-1, j-S[i])=True,这样就能通过递归法找到s中的元素了。对于这个问题,只要从subset(n, M)开始即可。

他觉得自己的思路是可行的,于是就在哥哥的程序上修改了起来:

import numpy as np# A Dynamic Programming solution for subset sum problem
# Returns true if there is a subset of set with sum equal to given sumdef isSubsetSum(S, n, M):# The value of subset[i, j] will be# true if there is a subset of# set[0..j-1] with sum equal to isubset = np.array([[True]*(M+1)]*(n+1))# If sum is 0, then answer is truefor i in range(0, n+1):subset[i, 0] = True# If sum is not 0 and set is empty,# then answer is falsefor i in range(1, M+1):subset[0, i] = False# Fill the subset table in bottom-up mannerfor i in range(1, n+1):for j in range(1, M+1):if j < S[i-1]:subset[i, j] = subset[i-1, j]else:subset[i, j] = subset[i-1, j] or subset[i-1, j-S[i-1]]# print the True-False tablefor i in range(0, n+1):for j in range(0, M+1):print('%-6s'%subset[i][j], end="  ")print(" ")if subset[n, M]:print("Found a subset with given sum")sol = []# using backtracing to find the solutioni = nwhile i >= 0:if subset[i, M] and not subset[i-1, M]:sol.append(S[i-1])M -= st[i-1]if M == 0:breaki -= 1print('The solution is %s.' % sol)else:print("No subset with given sum")# test
st = [1, 3, 4, 5]
n = len(st)
sm = 7
isSubsetSum(st, n, sm)

输出结果如下:

True    False   False   False   False   False   False   False
True    True    False   False   False   False   False   False
True    True    False   True    True    False   False   False
True    True    False   True    True    True    False   True
True    True    False   True    True    True    True    True
Found a subset with given sum
The solution is [4, 3].

  终于解决了这个问题,小连长舒一口气,而站在一旁的丁丁,看着弟弟的程序,也露出了满意的微笑~~
  晚饭后,哥俩正坐在门口的大树下乘凉,一旁的大雄急匆匆地跑过来来他俩帮忙。原来,他也碰到了一道难题,题目是这样的:

对于一个由若干个正整数组成的集合S,如何将S划分成两部分,使得两部分的和一样?

丁丁和小连看了题目,微微一笑,因为答案就在他们刚才解决的问题中。那么,亲爱的读者,你能尝试着解决这道问题吗?

动态规划法(三)子集和问题(Subset sum problem)相关推荐

  1. Subset sum problem

    给一个整数集合s和一个整数n,请问s中是否存在一个子集合,这个集合里的元素和 等于 n 采用动态规划进行求解: 1. 设集合x的最小和以及最大和分别是min,max,设一个二维数组 m[n][max- ...

  2. NYOJ 927 The partial sum problem 【DFS】+【剪枝】

    The partial sum problem 时间限制:1000 ms  |  内存限制:65535 KB 难度:2 描写叙述 One day,Tom's girlfriend give him a ...

  3. c语言sum出错,ACM:Sum Problem 求和问题C语言源码

    学习过程中,将写内容过程中重要的一些内容片段备份一下,如下内容段是关于ACM:Sum Problem 求和问题C语言的内容,应该是对码农们有一些用途. #include using namespace ...

  4. HDU.1001 Sum Problem

    原题 HDU.1001 Sum Problem 分类 杂题 题意 计算从1到正整数n的累加和. 输入/输出 要求与格式 输入内容 每行输入一个正整数 输出结果 结果为累加和 输出格式 每个输出结果独占 ...

  5. hdu 2058 解题报告 - The sum problem

    hdu 2058 解题报告 - The sum problem 传送门:http://acm.hdu.edu.cn/showproblem.php?pid=2058 等差求和公式: Sn=(a1+aN ...

  6. 牛客多校第三场 B【Classical String Problem】

    牛客多校第三场 B[Classical String Problem] 链接:https://ac.nowcoder.com/acm/contest/5668/B 来源:牛客网 题目描述 Given ...

  7. leetcode 416. Partition Equal Subset Sum | 416. 分割等和子集(Java)

    题目 https://leetcode.com/problems/partition-equal-subset-sum/ 题解 乍一看是背包问题,但不同的是,本题要求结果等于某值,背包要求结果小于某值 ...

  8. LeetCode Partition Equal Subset Sum(动态规划)

    问题:给出一个数组,问是否可以分成两个子集,其和相等 思路:首先要求数组和是偶数,然后用动态规划来求. 用dp(i,j)表示第i步时和为j是否可行,则有dp(i,j)= dp(i-1,j) || dp ...

  9. leetcode416. Partition Equal Subset Sum

    题目要求 Given a non-empty array containing only positive integers, find if the array can be partitioned ...

最新文章

  1. 苹果手机透明桌面_打开手机这个设置,桌面变全透明!
  2. Navicat for MySQL在ubuntu下运行没有反应
  3. Qt 有层级关系的qss样式,使用id定位到具体控件
  4. 王者荣耀交流协会第四次Scrum立会
  5. 自我觉察-3:发现-我这么做究竟为了什么?
  6. mvc5控制器修改html,关于jquery:如何通过对控制器的ajax调用在MVC5中呈现局部视图并返回HTML...
  7. 【调用IP宏文件进行仿真】modelsim仿真时出现 Instantiation of 'xxx' failed. The design unit was not found....
  8. 计算机专业跨考学科英语难吗,跨考学科英语,过来人走过的弯路
  9. 常用的字符串分割方法
  10. linux基础学习【6】
  11. Django(五):后台管理平台admin
  12. 运用计算机辅助教学,如何的运用计算机辅助教学.doc
  13. 软件配置管理(SCM)介绍
  14. 那款软件可以测试平板电脑性能,性能测试和应用体验
  15. Python:给信号添加白噪声
  16. java模拟填充网页表单_Java模拟form表单提交普通参数和文件
  17. 论文阅读(9) 鱼类洄游粒子图像测速技术综述 (2016)
  18. 戴尔t420服务器重装系统教程,教你联想t420系统重装步骤
  19. java判断闰年中闰月_编程序:计算某年某月有多少天(区分闰年和闰月)?怎么编?...
  20. 汽车ESP系统建模及仿真研究(2022-09-20)

热门文章

  1. 苹果M1/M2 Mac正式支持运行Win11
  2. 先锋FH-P8000BT汽车音响播放器 - 电源盒装
  3. 人工智能 对比试验_人工智能安全——对抗攻击分析
  4. 一点排位就安全异常退出_CF穿越火线新视界,版本大改动,你准备回归还是退出?...
  5. 亲测!UEFI启动模式下,电脑安装win10和Ubuntu双系统
  6. Gin+getway+Fabric2.4.4演示(一)从账本读数据
  7. 【车间调度】鸟群算法求解车间调度问题【含Matlab源码 1395期】
  8. 【投资理财】期权的价值
  9. h5引用项目里css_HTML中引入CSS 的方式
  10. RocketMQ消息存储之刷盘机制(原理篇)