动态规划: Subset Sum

这次我想给大家分享的内容是动态规划Subset Sum (子集之和)问题 。其实挺枯燥的,涉及到的是数学和编程方面的内容,如果不感兴趣请直接退出阅读。

本文概要:

  • Subset Sum 问题描述
  • 问题求解思路
  • 递归法求解
  • 重点:动态规划法求解

Subset Sum 问题


假设有一串 { 1,2, 4,5,6} , 是否存在任意数字之和为 7 , 55 。
通过目测 { 1, 2,4} {5, 2} 之和为7,所以答案为存在,因为所有元素之和小于55,所以答案为不存在。

问题:

假设有一个非负整数的集合 Set ,求是否存在一个组合使得其中任意元素之和为一个给定的整数 sum ?

A = { X1,X2,....Xn}, sum = Y
subset(A,Y) = True or False ?

求解思路


  1. 我们立马能想到第一个方法是先求解集合A 所有的排列组合,一共有2的5次方种可能,然后逐一对组合求和判断是否等于6。这种思路属于暴利求解法,当集合元素非常多的时候,计算时间会指数级增长,该算法的时间复杂度为O(2^n)。

  2. 第二种求解方法的思想是 把大事化小,小事化无的

如: A = { 1,2, 4,5,6} 可以简化为 { 2, 4,5,6 } 这个子集合元素是否有sum = 6 的解,或者{ 2, 4,5,6 } 是否存在相加之和为5 的解 。依次类推可以将问题一层一层缩小,利用上篇文章提到的递归思想。

递归求解法


arr  = [1,2 ,4,5,6]

def  subset(arr , i , s):
    if i == 0:
        return s == arr[0]
    elif s == 0:
        return True
    elif arr[i] > s :
        return rec_subset(arr, i-1 , s)
    else:
        A =  subset(arr , i-1 ,s - arr[i])
        B =  subset(arr, i-1 , s)
        return A or B
    
print( subset(arr ,len(arr )-1, 7))
out: True

通过递归方式来求解必须遍历所有的子问题,但其中子问题有重叠的部分,也就是说存在重复计算的情况,算法时间复杂度为O(2^n)。对于规模比较大的问题这是无法容忍的。接下来通过动态规划的方法 ,来避免重复计算来优化程序的性能。

动态规划求解法


动态规划是从下往上(bottom-up)的求解方法,并且把中间结果缓存起来避免重复计算。
例如:把{ 1,2, 4,5,6} 分解成 空集 0 { } ,1 { 1 } ,2 { 1,2 } ,3 { 1,2, 4 }, ,4 { 1,2, 4,5 } ,5 { 1,2, 4,5,6} 分别来计算,具体流程如下。

  1. 构建一个二维数组Subset[i,j] 来存放子集合相加和的所有可能情况,True(以下记为T)表示存在解,False(以下记为F)表示不存在解。
step1

如图1: 行为子集相加为0-7所有的情况,列为0-5个元素的所有情况。
第一行表示: 除了第一列为0存在解标记为T 之外,其余1-7都为 F 。

第一列表示:各个子集相加之和为0的情况。例如 {1 } 的情况显然如果 不取元素1 空集{}之和存在0的解,类似{1,2} 也有存在0的解,因此第一列都为T。

第二行第二列:表示{1} 之和为1,显然为T 。

第二行其余列:因为最大为1,所以余下都为F。

step2

中间任意一个格子计算方法,分两种情况。

如果格子上方为T,当前格子也为T。实际意义为:当前集合的子集如果有解那么,当前集合也有解,如{1,2,4} 之和3的情况,因为 {1,2} 存在之和为3的解。
因此得出结论,只要T下方的格子都可以设置为T。

如果格子上方为F, 则求 sum - A 余下子集合的解。例如上图绿色标记的位置 Subset[2,4] , 可以简化为求解 { 1 } 是否有 1的解,查表值为T,当前表格值则 为T。

用此算法,把表格填满。

step3

表格最后一个元素就是 { 1,2, 4,5,6} 是否存在子集合之和为7 这个问题的解。

具体的代码实现:


import numpy as np

def dp_subset(arr,S):
    
    subset = np.zeros((len(arr),S+1),dtype=bool) #构造二维数组
    subset[:,0] = True # 第一列 设为True
    subset[0,: ] = False #第一列 设为 False
    subset[0,arr[0]] = True
    
    for i in range(1,len(arr)):
        for s in range(1, S+1):
            if arr[i] > s:
                subset[i , s] = subset[i-1 , s]
            else:
                A = subset[i-1 , s ]
                B = subset[i-1 , s - arr[i]]
                subset[i,s] = A or B
                
                
    row ,cell = subset.shape
    return subset[row-1,cell-1]
            
arr  = [1,2, 4,5,6]            
dp_subset(arr,7) 
out:True

参考


  1. 视频讲解动态规划

  2. Dynamic Programming – Subset Sum Problem

  1. Algorithm/Insights
最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 213,186评论 6 492
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 90,858评论 3 387
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 158,620评论 0 348
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 56,888评论 1 285
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 66,009评论 6 385
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 50,149评论 1 291
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 39,204评论 3 412
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 37,956评论 0 268
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 44,385评论 1 303
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 36,698评论 2 327
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 38,863评论 1 341
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 34,544评论 4 335
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 40,185评论 3 317
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 30,899评论 0 21
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 32,141评论 1 267
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 46,684评论 2 362
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 43,750评论 2 351

推荐阅读更多精彩内容

  • 分治策略 本文包括分治的基本概念二分查找快速排序归并排序找出伪币棋盘覆盖最大子数组 源码链接:https://gi...
    廖少少阅读 1,844评论 0 7
  • 使用swift的Bundle来获取项目的文件路径 , 代码如下: 一直打印获取路径失败 解决方案: 打开build...
    红姑娘阅读 3,083评论 0 1
  • 炎热的度假时光马上就要开始了,一想到可以到海边或者游泳池就觉得很兴奋。不过,想要出门的话当然也要专门准备必备单品。...
    D3舍阅读 591评论 0 1
  • 有时候我觉得自己很多事不能做,做不好,女儿还小很多不懂,在去往西安游玩的火车上,女儿与一个八岁男孩子的对话提醒了我...
    幼学琼林阅读 186评论 0 0
  • 每天依旧繁忙,从早到晚。一下班,人就精神抖擞,上班,人就没有了精神。有点滑稽和可笑。 清早,...
    寻觅最青春阅读 224评论 0 0