题目描述:
现有十个分别标有1-10号码的球,十个分别标有1-10号码的罐子。每个球放进一个罐子里,现要求每一个球都不能放在同一号码的罐子中,请问有多少种放法?
1.1. codeball.py
<script type=text/javascript> function isnumbered(obj) { return obj.childNodes.length && obj.firstChild.childNodes.length && obj.firstChild.firstChild.className == 'LineNumber'; } function nformat(num,chrs,add) { var nlen = Math.max(0,chrs-(''+num).length), res = ''; while (nlen>0) { res += ' '; nlen-- } return res+num+add; } function addnumber(did, nstart, nstep) { var c = document.getElementById(did), l = c.firstChild, n = 1; if (!isnumbered(c)) if (typeof nstart == 'undefined') nstart = 1; if (typeof nstep == 'undefined') nstep = 1; n = nstart; while (l != null) { if (l.tagName == 'SPAN') { var s = document.createElement('SPAN'); s.className = 'LineNumber' s.appendChild(document.createTextNode(nformat(n,4,' '))); n += nstep; if (l.childNodes.length) l.insertBefore(s, l.firstChild) else l.appendChild(s) } l = l.nextSibling; } return false; } function remnumber(did) { var c = document.getElementById(did), l = c.firstChild; if (isnumbered(c)) while (l != null) { if (l.tagName == 'SPAN' && l.firstChild.className == 'LineNumber') l.removeChild(l.firstChild); l = l.nextSibling; } return false; } function togglenumber(did, nstart, nstep) { var c = document.getElementById(did); if (isnumbered(c)) { remnumber(did); } else { addnumber(did,nstart,nstep); } return false; } </script> <script type=text/javascript> document.write('
Toggle line numbers '); </script>
Toggle line numbers
1 # -*- coding: utf-8 -*-
2
3 #号码球问题
4
5 #求排列,这里采用迭代算法而非递归,
6 #是为了得到更好的效率
7 def P(x, y = None):
8 """
9 求排列数P(x, y),y默认值为x,此时取P(x),即x!
10 """
11 if x == 0 or y == 0:
12 return 1
13
14 re = x
15 i = x - 1
16 if y == None:
17 l = 1
18 else:
19 l = x - y
20
21 while i > l:
22 re *= i
23 i -= 1
24 return re
25
26 #求组合
27 def C(x, y):
28 """
29 求组合数C(x, y)
30 """
31 if x == y:
32 return 1
33 else:
34 return P(x, y)/P(y)
35
36 #求号码球(Code Ball)问题,CB1使用递归算法:
37 #1、CB1算法只考虑取出所有球的情况
38 # 即每一个罐子都有一个球对应,没有空罐。
39 #2、CB1(0)时,视作有1种解(这种情况下没
40 #有罐子与球对应);
41 #3、CB1(1)时,没有解(罐子必然与球对应);
42 #4、CB1(2)时,有一种解(罐子与球要么完全)
43 #对应,要么完全不对应;
44 #5、CB1(n), n>=3可以分解为用所有可能的排列减去
45 #不合要求的组合。包含有m(m <= n)个重复对应的排
46 #列数为C(n, m)*CB1(n - m)。m取遍n到1,
47 #P(n)与C(n, m)*CB1(n - m)之积加和之差,即为所求。
48 #故:
49 #CB1(3) = P(3) - C(3, 3)*CB1(3 - 3) - C(3, 2)*CB1(3 - 2) - C(3, 1)*CB1(3 - 1)
50 #CB1(n) = P(n) - C(n, n)*CB1(n - n) - C(n, n - 1)*CB1(n - n + 1) - ... - C(n, 1)*CB1(n - 1)
51 # = P(n) - C(n, n)*CB1(0) - C(n, n - 1)*CB1(1) - ... - C(n, 1)*CB1(n - 1)
52 #由C(n, n)==1,CB1(0)==CB1(2)==1,CB1(1)==0,CB1(n)可以简化为:
53 #CB1(n)=P(n) - 1 - C(n, n - 2) - C(n, n - 3)*CB1(3) - ... - n*CB1(n-1)
54 def CB1(x):
55 if x == 0 or x == 2:
56 return 1
57 elif x == 1:
58 return 0
59 else:
60 re = P(x) - 1
61 for i in range(2, x):
62 re -= C(x, x-i)*CB1(i)
63 return re
64
65 print "CB1算法解得CB1(10) = ", CB1(10)
2. Zoom.Quiet
坚决使用暴力!
使用"一切从游戏开始 - ChinesePython Wiki"的技巧来优化
2.1. codeBall.py