一、前言
關於本文中用到的這種圖着色解決方法,不知道有沒前人提出過。如果說沒人提出過,那么就算是一個新的解決方法吧,具體性能對比沒深入研究,但是求出的解基本是和Graph Coloring Instances網站里面的最優解一樣的。
我們都知道,很多問題都可以轉化成圖着色問題來進行解決,所以本文的例子直接是無向圖。
二、解決思路
不太成熟的想法:
要使得相鄰點的顏色不同,着色方案有很多種,那么究竟哪種着色方案使用的顏色最少呢?
首先最開始看到這個問題時,我最開始的思路是每次用盡量少的顏色給盡量多的點上色。
->
->
->
->
->
以上是個簡單的圖,我選用的步驟為:
1、找出度最大的頂點2、3、5(度均為4)。
2、對2着色C1,然后遍歷相鄰點
3、給1着色C2
4、給3着色C2,和1沖突,着色C3
5、給5着色C2,不沖突
6、給4着色C2,與5沖突,着色C3
7、給4着色C1,不沖突
從一次性上完一種顏色入手:
本來是想實現上一個想法的,但是在梳理的過程中,有一個新的想法,即是通過與以前運籌學課程上學過的方法結合,較為高效且高質量地解決問題。
步驟如下:
步驟一、給未上色點集中度最大的頂點上色Ci,生成可同色點集,為與該頂點不相鄰且未上色的點的集合
步驟二、遍歷可同色點集,給點集中的點上色Ci,每上完一個點就生成一次可同色點集,為與上Ci點不相鄰且未上色的點的集合,直到可同色點集為空
步驟三、更新未上色點集,i=i+1,回到步驟一
例:以下是myciel3.col數據的圖,求最少能上幾種顏色。
鄰接矩陣為
每個頂點的度為4、4、4、4、4、3、3、3、3、3、5,度最大的頂點為第11個頂點。
1、給V11上色C1,可同色集為{V1,V2,V3,V4,V5}
2、給V1上色C1,可同色集為{V3,V5}
3、給V3上色C1,可同色集為{}
4、給V2上色C2,可同色集為{V4,V7,V9,V10}
5、給V4上色C2,可同色集為{V7,V9}
6、給V7上色C2,可同色集為{V9}
7、給V9上色C2,可同色集為{}
8、給V5上色C3,可同色集為{V6,V8,V10}
9、給V6上色C3,可同色集為{V10}
10、給V10上色C3,可同色集為{}
11、給V8上色C4,可同色集為{}
上色后的圖:
顏色使用了4種,和已知最優解一樣。
三、python代碼實現
1 def getAdjMatrix(path): 2 edge = [] 3 pointNum = 0 4 with open(path, 'r') as fp: 5 for line in fp.readlines(): 6 if line.startswith('p'): 7 pointNum = int(line.split()[2]) 8 for i in range(pointNum): 9 edge.append([0 for i in range(pointNum)]) 10 if line.startswith('e') and pointNum > 0: 11 edge[int(line.split()[1]) - 1][int(line.split()[2]) - 1] = 1 12 edge[int(line.split()[2]) - 1][int(line.split()[1]) - 1] = 1 13 return edge, pointNum 14 15 16 def main(): 17 edge, pointNum = getAdjMatrix(r'F:\timFilm\test.txt') 18 print('') 19 for i in edge: 20 print(' ', end='') 21 for j in i: 22 print(j, end='\t\t') 23 print('\n') 24 colorNum = 0 25 disabled = [] 26 27 # 初始化color列表,用以記錄每個頂點的着色情況 28 color = [] 29 for i in range(pointNum): 30 color.append(0) 31 edgeNum = [sum(e) for e in edge] 32 for k in range(pointNum): 33 # 獲取頂點最大度的索引值 34 maxEdgePoint = [i for i in range(pointNum) if edgeNum[i] == max(edgeNum) and edgeNum[i] != 0] 35 # 遍歷最大度 36 for p in maxEdgePoint: 37 if p not in disabled: 38 # 選取還未着色且度最大的點p開始着色 39 color[p] = colorNum + 1 40 disabled.append(p) 41 edgeNum[p] = 0 42 # temp用於查找該顏色可用來着色的下一個頂點 43 temp = edge[p] 44 for i in range(pointNum): 45 if i not in disabled: 46 if temp[i] == 0: 47 # 為不沖突的頂點着色 48 color[i] = colorNum + 1 49 disabled.append(i) 50 edgeNum[i] = 0 51 # 增加當前顏色的禁忌點 52 temp = [x + y for (x, y) in zip(edge[i], temp)] 53 # 需要新顏色 54 colorNum = colorNum + 1 55 56 # 每個頂點都已經着色 57 if 0 not in color: 58 break 59 print(color) 60 print(colorNum) 61 62 63 main()