给出一个清单
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]
(我在这里没有线索)?
答案 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
是具有度矢量ms
和cs
的二分图的数量。但是这个定义在ms
和cs
方面是对称的!所以nbOfLists
也必须是对称的。
我不知道是否存在针对此问题的非暴力算法,但我希望我至少澄清了一点。