編程練習(四)(拉丁方和放球問題)

拉丁方

  • 問題描述
    拉丁方又稱拉丁圖,是一種 n × n 的方陣,在這種 n × n 的方陣裏,恰有 n 種不同的元素,每一種不同的元素在同一行或同一列裏只出現一次。

  • 思路解析
    每次對矩陣中的一位賦值,就進行一次條件檢查,利用窮舉的辦法得出所有矩陣。

  • python語言實現如下

def matrix_formation(x, y, n):  # 生成所有符合的矩陣並計數
    global counting
    global num
    global matrix
    if counting == (n*n):
        matrix_print(n)  # 若內容已生成,輸出矩陣並計數
        num += 1
    else:
        for i in range(1, n+1):  # 產生矩陣內容
            matrix[x][y] = i
            counting += 1
            if martix_inspection(x, y):
                x1 = x
                y1 = (y + 1) % n
                if y == (n - 1):
                    x1 = x + 1
                matrix_formation(x1, y1, n)
            counting -= 1  # 遞歸完成後重新生成矩陣


def martix_inspection(x, y):  # 檢查元素是否在同行同列出現
    global matrix
    ins_num = matrix[x][y]
    for i in range(y):
        if ins_num == matrix[x][i]:
            return 0
    for i in range(x):
        if ins_num == matrix[i][y]:
            return 0
    return 1  # 符合條件返回1


def matrix_print(n):  # 輸出矩陣
    for i in range(n):
        for j in range(n):
            print(matrix[i][j], end=' ')
        print('')
    print('')


a = int(input("請輸入方針階數:"))
print('')
print("符合條件方陣如下:")
print('')
global counting, num, matrix  # 定義全局變量
counting = 0
num = 0
matrix = [[0] * a for _ in range(a)]
matrix_formation(0, 0, a)
print("可得:%d階方陣有%d個拉丁圖" % (a, num))


放球問題

  • 問題描述
    放球問題是一類經典問題,即把n個小球放到k個盒中,小球是否有區分,盒子是否有區分,盒子是否爲空,n和k的大小比較,這些情況可以組合成不同的場景,有着不同的解決方法。該類問題在網上有着專門的百科分析,直接搜索“放球問題”即可得到各種情況的解析。

  • 思路解析
    本次針對的場景是:小球有區分,盒子有區分,盒子不能爲空。首先假設盒子不可區分,計算可能方案可採用第二類斯特林數公式進行計算,即S(n,k)=S(n-1,k-1)+k*S(n-1,k), 再計算可區分的盒子排列,即爲k的階乘,因此總的方案數num=S(n,k)*k!。

  • python語言實現如下

from numba import jit


@jit(nopython=True)  # 加快計算速度
def stirling(n, k):  # 第二種斯特林數公式,即S(n,k)=S(n-1,k-1)+k*S(n-1,k)
    if k > n or k == 0:  # 若盒數大於球數,一定有盒子爲空;若盒數爲0,不滿足條件
        return 0
    elif k == n:  # 若盒數等於球數,就只有一種辦法
        return 1
    elif k == 1:  # 若盒數爲1,也只有一種辦法
        return 1
    return stirling(n-1, k-1) + stirling(n-1, k) * k


n = int(input("請輸入小球數量:"))
k = int(input("請輸入盒子數量:"))
num = 1
for i in range(1, k+1):  # 計算k的階乘
    num = num * i
num = num * stirling(n, k)  # 假設盒子是無區別的,即有S(n,k)種方案,再對盒子排列,有k的階乘種
print("%e" % num)
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章