更快的组合功能

时间:2011-01-23 20:02:47

标签: math haskell combinatorics

给出一个清单

ms = [2,1,1,1]  

of multiplicities,一个与ms对应的素数(此处,股票可以是:2,2,3,5,7)和一个长度为lc的列表,

cs = [3,1,1]

的容量,我们考虑任何长度lc的列表xs,使得xs !! i =来自股票的(cs !! i)数字的乘积,0< = i< lc,在xs构造结束时库存为空(所以

sum ms == sum cs 

应该坚持)。

例如,以下是具有所选股票的xs的13种可能性:

  [12,5,7], [12,7,5], [20,3,7], [20,7,3]
, [28,3,5], [28,5,3], [30,3,7], [30,7,3]
, [42,2,5], [42,5,2], [70,2,3], [70,3,2], [105,2,2].

编程问题是写一个快速函数

nbOfLists :: (Integral a,Integral b) => [a] -> [a] -> b  

计算不同的此类列表的数量(此处为nbOfLists ms cs == 13)。

这是Haskell的解决方案

nbOfLists [u] _     = 1
nbOfLists (u:us) vs = 
    let clean = map (filter (/=0))
        corpus = filter (all (>=0)) $ map (zipWith (-) vs) $ base u (length vs)
        base k 1 = [[k]]
        base k l = concat [map (i :) $ base (k-i) (l-1) | i <- [0..k]]
    in sum $ map (nbOfLists us) $ clean corpus

在10秒内执行nbOfLists [2..6] [2..6] == 604137。你能做得更好吗?

顺便问一下,你能证明nbOfLists ms cs == nbOfLists cs ms?也就是说,例如,从2,2,2,3,5股票中,xs是13个列表中的一部分:

  [4,2,3,5], [4,2,5,3],  [4,3,2,5],  [4,3,5,2]
, [4,5,2,3], [4,5,3,2],  [6,2,2,5],  [6,2,5,2]
, [6,5,2,2], [10,2,2,3], [10,2,3,2], [10,3,2,2], [15,2,2,2]

(我在这里没有线索)?

1 个答案:

答案 0 :(得分:1)

这就是问题所在。我们得到一组由列表ms表示的几种类型的项目。例如,ms=[2,1,1,1]表示我们有2个第一类型的项目,1个第二类型的项目,依此类推。我们想要计算将所有项目放入lc框的方式的数量,以便i - 框包含cs!!i项。

我将回答你关于对称性的问题:你能证明nbOfLists ms cs == nbOfLists cs ms吗?让我们用二分图来编码项目的每个分布。一个部分的节点将对应于项目的类型,另一个部分的节点对应于框,并且每次我们将i类型的项目放到j - 框时我们将绘制边缘i-j。问题的条件意味着第一部分中的节点的度数必须等于ms,并且第二部分的节点的度数必须等于cs。因此,nbOfLists是具有度矢量mscs的二分图的数量。但是这个定义在mscs方面是对称的!所以nbOfLists也必须是对称的。

我不知道是否存在针对此问题的非暴力算法,但我希望我至少澄清了一点。