这周接触了离散数学的第一章,也就是基础章节,主要是集合论、递推式、组合排列数方面的基础知识。这里含有关于递推式的一道题目。
最本来的解法是采用了递推式进行求解,但是我想到了一种组合排列数的解法。
一、原始题目:
使用多米诺骨牌,即1x2的小方格,覆盖2 x n的方格棋盘,有多少种不同的方式?
二、递推关系进行求解:
从题目而言,我们发现的递推关系是:当为n时,只考虑最右边的竖着的两个方格,如果用一个竖立的多米诺骨牌进行填充,那么此时的填充方式跟n-1时的一致,如图a所示;而如果用两个横着的多米诺骨牌填充,那么此时的填充方式数目跟n-2时的一致,如图b所示。
图a
图b
因此我们可以得到这样的递推式子,即f(n)=f(n-1)+f(n-2),也就是2-阶常系数齐次递推关系式,更准确些,该式就是斐波那契数列,但是初值时f(1)=1,f(2)=2。
我们采用2-阶常系数齐次递推关系式的通用解法,如下如所示:
图c. 2-阶常系数齐次递推关系式的通用解法
三、组合排列数解法
组合排列数解法,其中心思想就是可重排组合数,以及本题目的一个重要特性:填充的多米诺骨牌中,横着的个数一定是2的倍数,即如图所d所示。因为图e所示的情况不会出现,出现的话,将导致无法填充满这个2 x n的区域。
图d
图e,无法完全填充的情况
因此,我们可以如此进行数学说明:假设竖着排列的骨牌个数为a,横着排列的骨牌个数为b,那么如果填充满整个区域,则存在着这样的关系式a+2*(b/2)=n,即a+b=n,从容斥定理来看,这也是必然的。
因此,如果a,b确定后,问题就变成了a个竖立的和b/2个横着的骨牌如何排列组合的问题,相当与把b/2个相同的苹果,放入(a+1)个不同的盒子的问题,即是可重排组合数,其组合数为C(a+1+b/2-1,b/2)=C(a+b/2, b/2)=C(n-b/2, b/2)。
如此,我们就知道了当a,b确定后,此时的情况个数为多少了。
而另一方面,我们知道,对于任何一个n,b的情况为1+(n//2)种 ,那么我们可以得到f(n)如下所示:
四、验证
看起来上述的两种方法得到了完全不同的结果,但是实际上两者是完全一致的。利用两种不同的解法,我通过python验证了两者的结果,我的验证结果如下所示,combine是采用第二种解法得到的曲线,facb是采用斐波那契数列的结果,x轴表示n,y轴表示2 x n时的有多少种填充方式:
五、python代码如下所示:
import math
import numpy as np
import matplotlib.pyplot as plt
# 通过斐波那契数列进行计算
def facb(n):
if n == 1:
return 1
elif n == 2:
return 2
n -= 1
a0 = (3*math.sqrt(5)+5)/10
b0 = (3*math.sqrt(5)-5)/10
a = (1+math.sqrt(5))/2
b = (1-math.sqrt(5))/2
return a0*math.pow(a,n)+b0*math.pow(b,n)
# 阶乘函数
def factorial(num):
# 查看数字是负数,0 或 正数
if num < 0:
print("抱歉,负数没有阶乘")
return None
elif num == 0:
print("0 的阶乘为 1")
return 1
else:
factorial = 1
for i in range(1, num + 1):
factorial = factorial * i
print("%d 的阶乘为 %d" % (num, factorial))
return factorial
# 以下是自己通过组合数进行得到的结果
def comb(n):
b = [i//2 for i in range(n+1) if i%2==0]
res = 0
for i in b:
m = n - i
res += factorial(m)/(factorial(m-i)*factorial(i))
return res
def test_two(n):
x = np.arange(1, n + 1)
yc = []
yf = []
for i in x:
yc.append(comb(i))
yf.append(facb(i))
yc = np.array(yc)
yf = np.array(yf)
plt.xlabel('n')
plt.ylabel('number')
plt.plot(x, yc, "x-", label='combine')
plt.plot(x, yf, "+", label='facb')
for xy in zip(x, yc):
plt.annotate(str(int(xy[1])), xy=xy)
plt.grid()
plt.legend()
plt.savefig("两者的结果.jpg")
plt.show()
if __name__ == '__main__':
test_two(10)