k图着色 局部搜索算法与模拟退火算法的python实现

本文介绍了如何使用Python实现k图着色问题的局部搜索和模拟退火算法。通过计算冲突节点来评价解的质量,并以此生成邻居解。在局部搜索中,使用numpy矩阵加速计算,而在模拟退火算法中,通过调整温度和下降率快速收敛,实现在2秒内找到500节点的3色最优解。文章还指出了算法存在的问题和改进空间。
摘要由CSDN通过智能技术生成

前言

这两种算法就不详细介绍了,流程思路比较简单,而且两者对代码逻辑稍作修改便可互换,但都需要面对的两个主要问题是:

如何评价一个解?

这里使用了颜色集合来先对节点进行归类,对所有的节点随机的赋以颜色(这里用数字做代替),然后再按照颜色对其归类,集合的数量对应为颜色的数量。然后在一个颜色子集合中取所有任意两个点来判断他们是否是连通的即可,若是连通这两个便是冲突的,可将其存储并计数,找到所有的冲突节点和数量,这便是评价解是否优秀的一种方法。

通过计算出的冲突来找它的邻居解

在找到冲突的节点之后,便可以由此来生成邻域解。大致做法是:以先前按照颜色划分的集合为基础,将这个冲突的节点从这个颜色集合中取出,再依次放入其他颜色的节点,这样就生成了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
评论 3
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值