今天在网上看见这么一道题目:给你m个数,从里面找出和为sum的n个数,问一共能找到多少组这样的 数。
根据我的理解,这是一道组合生成的题目。令m个数组成的集合为M,就是要找到所有元素个数为n且和 为sum的子集。
最笨的方法是生成所有的子集,然后进行验证,这样复杂度为阶乘。显然有一种改进的算法,在笨方 法中,我们连元素个数不为n的子集都生成了,而这显然是不必要的。这种改进想到很容易,但实现起来 有点困难,经过数个小时的艰苦奋战,我终于设计了一种原创性的组合生成算法,虽然它应该早被计算机 科学家想到了,但我还是抑制不住激动。
我们知道元素个数为m的几何,它的大小为n的子集的个数肯定是C(m,n),由于博客园不能用Tex写公式 ,我只能这样表示组合公式。理想的算法应该是只生成这些子集,这谁都知道,关键是怎么通过一种可列 的方式来生成它们。
我们用一个二进制数来表示集合,用一个二进制位来表示元素,相应位是1则说明集合包含该元素,否 则不包含。先考虑一个特例,集合A的大小为5,生成所有大小为3的子集。显然 00111符合条件,01011也 符合条件,还有01110、01101,但是我们不能瞎猜吧。下面我画出树图,也是我的思维图。
上图就是5选3的结果,现在我们来分析一下怎么由父结点生成子结点,根结点可以很容易求出来,如 果知道如何由父生成子,那么整个问题就解决了。我用序对(p,q)表示将第p位变为1,第q位变为0,注 意下标从0开始。请检查下列序对是否有00111生成了他的5个儿子。
(3,0)
(3,1)
(3,2)
(4,1)
(4,2)
请认真验证上面的操作,有些东西是无法用语言来表达的,相信验证之后你就理解得差不多了。对, 红色的位置是分界线,p从红色的位置开始递增,而q是从0递增到红色位置的前面一位,反映在程序中应 该是个二层循环:外层是p在递增,内层是q在递增。