前言
这两种算法就不详细介绍了,流程思路比较简单,而且两者对代码逻辑稍作修改便可互换,但都需要面对的两个主要问题是:
如何评价一个解?
这里使用了颜色集合来先对节点进行归类,对所有的节点随机的赋以颜色(这里用数字做代替),然后再按照颜色对其归类,集合的数量对应为颜色的数量。然后在一个颜色子集合中取所有任意两个点来判断他们是否是连通的即可,若是连通这两个便是冲突的,可将其存储并计数,找到所有的冲突节点和数量,这便是评价解是否优秀的一种方法。
通过计算出的冲突来找它的邻居解
在找到冲突的节点之后,便可以由此来生成邻域解。大致做法是:以先前按照颜色划分的集合为基础,将这个冲突的节点从这个颜色集合中取出,再依次放入其他颜色的节点,这样就生成了k-1个邻域解(设k为颜色个数)。这样遍历所有颜色集合中的所有冲突节点便可生成全部的邻域解。评价出最好的一个邻域解进行下一次迭代即可。
数据的格式
python读取处理数据很方便啦~
20
0: 1 3 4 9 18 7 2 5
1: 16 5 7 2 17
2: 17 5 8
3: 7 18 5 2 11 17 10 13 9 16 4 12
4: 17 19 11 13 16 14 18 8
5: 17 9 15 8 2 10 13 6 3 12 4 14 11 7 0
6: 9 4 12 7
7: 11 16 15 17 6 18 4 8 10 14 1 13 0 19 9
8: 5 4 3 1 7 12 19 0 6 13
9: 12 1 10 17 6 13 0 5 7 11 3 19 2 15 4 18
10: 6 2 18 8 16 11 0 1 17 4 15 3 13
11: 7 17 8 13 12 2 14 9 18 15 19 1 4 0
12: 5 6 15 18 14 9 0 8 19 10
13: 0 19 9 10 2 11 18 15 12 16 1 4 5 7 6 17 14
14: 2 3 11 19 10 18 1
15: 18 8 9 16 2 3 14
16: 1 12 6 0 7 19 17 9 8 15
17: 16 2 1 12 5 7
18: 3 13 6 11 4 19 8 17 16 10 0 7 2 1 12 15 5 9 14
19: 11 1 7
500节点数据:data.txt
局部搜索
概述
这里将先前读取到的数据存储在字典之中,在将它转化为numpy矩阵进行存储,为的是后面方便直接使用numba来加速计算,性能提升的十分明显,这里在get_one_color_set_conflict(graph, color_set)
函数中使用了,有兴趣的可以关闭对比试下效果。
补充
在使用局部搜索算法时可以先假设一个解得序列,以一种方式来评价这个解得优秀性,这里使用冲突节点的多少来进行评判,再根据冲突节点来构造其领域解,如将这个冲突的节点放到其他颜色的集合之中,生成邻域解之后再进行评估,选择邻域解中的最优解,之后进行下次的迭代。
例如在本题目中的图可使用邻接矩阵或者邻接表的形式进行存储,如下:
1:2,3,4
2:1,5,9
3:1,8
4:1,7,8
5:2,6,8
6:5
7:4,8,9
8:3,4,5
9:2,7
可以将颜色用数字来代替:红,绿,蓝->0,1,2
可以使用随机的初始值{0: [1, 3, 5], 2: [2, 4, 8], 1: [6, 7, 9]},计算出冲突的节点,这里使用冲突对来表示各个颜色集合中的冲突{0: [[1, 3]], 1: [[7, 9]], 2: [[4, 8]]},共计有三对6个冲突节点,那么可以构造它的邻域解共计12个:
{
0: [3, 5],
2: [2, 4, 8],
1: [6, 7, 9, 1]
}, {
0: [1, 5],
2: [2, 4, 8],
1: [6, 7, 9, 3]
}, {
0: [3, 5],
2: [2, 4, 8, 1],
1: [6, 7, 9]
}, {
0: [1, 5],
2: [2, 4, 8, 3],
1: [6, 7, 9]
}, {
0: [1, 3, 5, 7],
2: [2, 4, 8],
1: [6, 9]
}, {
0: [1, 3, 5, 9],
2: [2, 4, 8],
1: [6, 7]
}, {
0: [1, 3, 5],
2: [2, 4, 8, 7],
1: [6, 9]
}, {
0: [1, 3, 5],
2: [2, 4, 8, 9],
1: [6, 7]
}, {
0: [1, 3, 5, 4],
2: [2, 8],
1: [6, 7, 9]
}, {
0: [1, 3, 5, 8],
2: [2, 4],
1: [6, 7, 9]
}, {
0: [1, 3, 5],
2: [2, 8],
1: [6, 7, 9, 4]
}, {
0: [1, 3, 5],
2: [2, 4],
1: [6, 7, 9, 8]
}
依次对这些邻域解进行评估,选择出当前邻域中最优的那一个解,也就是冲突数量最少的那个,再使用该解进行下一次迭代 ,直至求出0冲突的全局最优解。
不算伪代码的伪代码–>
使用局部搜索算法来求解3色最优解要花费大量的时间,其命中3色最优解的概率很小,非常容易陷入局部最优当中,在几百轮的(断断续续)重启计算后只得出了一次最优三色解。
代码
import random
import time
import numba as nb
import numpy as np
def get_graph(path):
g = {
}
f = open(path, 'r')
f.readline()
data = f.readlines()
for i in data:
i = i.split()
node = int(i.pop(0)[:-1])
i = list(map(int, i))
# print(node[:-1],i)
g[node] = i
# print(g)
return g
def ge