用Python解決計數原理問題的方法,python解決計數原理
前幾天遇到這樣一道數學題:
用四種不同顏色給三稜柱六個頂點塗色,要求每個點塗一種顏色,且每條棱的兩個端點塗不同顏色,則不同的塗色方法有多少種?
當我看完題目後,頓時不知所措。於是我拿起草稿紙在一旁漫無目的地演算了一下,企圖能找到解決方案。結果一無所獲。於是打算通過程式演算法解決這個問題。經過2個多小時的研究,終於完成了代碼,並求得了答案。
由於Python寫起來比較方便而且本人比較喜歡Python的文法,所以研究演算法時我通常採用Python,此次也不例外。以下就是整個演算法的實現過程。
兩種演算法
我一共想出了兩種用於解決本題的演算法:
演算法一:將所有的塗色情況通過程式的迴圈計算出來,然後通過程式的條件判斷去除掉不合題意的所有情況,最後得到最終結果。
演算法二:從其中任意一個端點(p0)入手,由於其它所有端點都沒有塗色,所以它可以塗四種顏色。將這四種顏色通過迴圈分別塗在這個端點上,每塗上一種顏色後,擷取與它相臨的一個端點(p1),並擷取它可以塗上的顏色,然後通過迴圈將可用顏色塗上(及不能塗上與p0相同的顏色),每塗上一種顏色,又將p1相鄰的未塗色的點塗色(及除p0外其他的相鄰端點)。每個點被塗色後都採用同樣的方法將相鄰的點塗色,以此類推,塗完最後一個點,就記一次情況。所有的遞迴都完成後,就獲得了所有情況。
演算法一很直接很粗暴,所以我採用了演算法二來解決上述問題。接下來就是具體的代碼了。
演算法實現
我寫了大約90行Python代碼來實現這個演算法:
colorList = [0, 1, 2, 3]pointList = []amount = 0class Point(object): def __init__(self): super(Point, self).__init__() self.neibors = [] self.color = None def paint(self, c): self.color = c def clean(self): self.color = None def getLeftOverColors(self): copyOfColorList = colorList[0 : 4] for neibor in self.neibors: nc = neibor.color if nc in copyOfColorList: copyOfColorList.remove(nc) return copyOfColorListdef main(): global pointList p0 = Point() p1 = Point() p2 = Point() p3 = Point() p4 = Point() p5 = Point() p0.neibors = [p1, p2, p4] p1.neibors = [p0, p2, p5] p2.neibors = [p0, p1, p3] p3.neibors = [p2, p4, p5] p4.neibors = [p0, p3, p5] p5.neibors = [p4, p3, p1] pointList = [p0, p1, p2, p3, p4, p5] paintPoint(p0) print(amount)def paintPoint(p): global amount colors = p.getLeftOverColors() lastOne = isLastOne() for c in colors: p.paint(c) if lastOne: amount += 1 else: for currentNeibor in p.neibors: if currentNeibor.color == None: paintPoint(currentNeibor) break p.clean()def isLastOne(): global pointList paintedNum = 0 for p in pointList: if p.color != None: paintedNum += 1 return paintedNum == 5if __name__ == "__main__": main()
以下是對各段代碼的介紹。
全域變數
colorList:顏色列表
pointList:存放六個點的列表
amount : 塗色方案的種數
Point類
用於儲存各個點的資訊,如點的顏色(color屬性,None代表無顏色)、相鄰的點('neibors'屬性)。以及提供paint方法用於將點標記顏色;clean方法用於去除顏色;getLeftOverColors方法用於擷取可用顏色,及擷取相鄰點沒有使用的顏色。
main函數
程式開始運行時調用的函數,其中構造了所需的六個點,以及分別為這六個點明確了相鄰的三個點。注意,由於這裡的點只有相鄰和不相鄰的位置關係,所以不需要在意這些點到底在三稜柱裡對應哪個位置,任意設定這些點的位置對結果來說並沒有影響,只需注意它們之間的相鄰關係即可。
isLastOne函數
判斷是不是最後一個未塗色的點。
paintPoint函數
用於對作為參數傳入的點進行著色。其中首先通過調用該點的getLeftOverColors方法擷取可用顏色,然後按照上文演算法中介紹的,通過遍曆可用顏色列表,為該點著色,如果該點不是最後一個點(通過isLastOne函數判斷),就遞迴調用paintPoint函數為相鄰的一個未著色的點著色,如果是,則將記下一次塗色方案。
運行代碼,得到結果 - 264:
Ok,於是這道題就在我們的電腦的協助下,被成功解決掉了~如果大家有更好的方案解決這一演算法問題,歡迎留言進行交流~希望本文對大家學習Python和計數原理都能有所協助。