算法老师留了个作业,让给出问题的一个算法,符合题目要求。其中一道题是这样的:
翻译一下:给出符合O(nt)
的算法,n
是正整数数组a[1], a[2], ..., a[n]
的长度;t
是正整数。判断数组a
的子集和是否等于t
?
这道题一看就是用dp思想解答,但是dp一直是算法的一个难点,经过各种查询,发现网上的答案给出的解释很简单,但是不容易看懂。本文写给dp思想掌握不好的同学,记录这道题的解决方法。
先分析题目:每个元素有两个不同的状态——选与不选。但是如果每个元素都进行相加判断,共需要 O ( 2 n ) O(2^n) O(2n)的时间。当我们遍历整个数组的时候,判断数组中每个元素与t
的大小关系(用 s u m s u b s e t ( i , t ) sumsubset(i,t) sumsubset(i,t) 表示子集前 a [ i ] a[i] a[i] 的和是否等于 t t t ):
- a [ i ] > t a[i] > t a[i]>t,则 a [ i ] a[i] a[i] 必然不在备选子集中。
- a [ i ] < t a[i] < t a[i]<t,则仍有2种情况:
(1) a [ i ] a[i] a[i] 确实是备选子集中,即 s u m s u b s e t ( i , t ) = t r u e sumsubset(i, t) = true sumsubset(i,t)=true. 此时有 s u m s u b s e t ( i , t ) = s u m s u b s e t ( i − 1 , t − a [ i ] ) sumsubset(i, t)=sumsubset(i-1, t-a[i]) sumsu