顶点着色问题

graphcoloring1 graphcoloring2
今天一个本科小学弟问到一个matlab编程问题,说自己只是改了别人的一小段代码,结果程序运行就通不过。给他看了一遍代码,我也没有发现问题。在一个for循环里面,第一遍能跑完,跑到第二遍的时候就会在一句调用 sum 函数的地方提示错误,反复对比单步调试无果。还多次确认, sum 函数本身并没有什么使用限制。后来突然灵光一闪,发现他的for循环里面用到一个变量名就叫 sum, 第一遍循环跑完后,sum变量进入工作空间,第二遍的时候,matlab只知道sum是个变量名,而小学弟的意图却是想调用 sum 函数。编程习惯不好害师兄啊。

然而我们今天要讲的却是程序中另外一个问题——顶点着色问题。回来仔细查找资料后,才发现这个顶点着色问题属于图论里面的一个小分支。可以在维基百科里面看到图的着色问题详细的介绍(https://en.wikipedia.org/wiki/Graph_coloring)。

顶点着色问题 vertex coloring

维基里面讲得很清楚了,图的着色问题可以退化到边的着色问题,边的着色问题可以退化到点的着色问题(vertex coloring)。

问题来源——四色问题

图的着色是由地图的着色问题引申而来:用 m 种颜色为地图着色,使得地图上的每一个区域着一种颜色,且相邻区域颜色不同。四色问题:“任何一张地图只用四种颜色就能使具有共同边界的国家着上不同的颜色。”

顶点着色问题的基本概念

m可着色:若一个图最少需要 m 种颜色才能使图中每条边连接的两个顶点着不同的颜色,则称m为该图的色数。求 m 的问题称为图的m可着色优化问题。

独立集:对图 G=(V,E) ,设 S V的一个子集,其中任意两个顶点在 G 中均不相邻,则称S G 的一个独立集。

最大独立集:如果G不包含适合 |S|>|S| 的独立集 S ,则称 S G的最大独立集。

极大覆盖: K G的一个独立集,并且对于 VK 的任一顶点 v , K+v都不是 G 的独立集,则称K G 的一个极大覆盖。

极小覆盖:极大独立集的补集称为极小覆盖。

V的子集 K G的极小覆盖当且仅当:对于每个顶点 v 或者v属于 K ,或者v的所有邻点属于 K (但两者不同时成立)。

顶点着色的算法思想

显然,同色顶点集实际上是一个独立集,当用第1种颜色上色时,为了尽可能扩大颜色1的顶点个数,逼近所用颜色数最少的目的,事实上就是找出图G的一个极大独立集并给它上色1。用第2种颜色上色时,同样选择另一个极大独立集上色, ,当所有顶点涂色完毕,所用的颜色数即为所选的极大独立集的个数。

需要说明的是,上述其和能够包含所有顶点的极大独立集个数未必唯一。

顶点着色问题的常用算法

回溯算法、分支定界法、Welsh Powell法、布尔代数法、蚁群算法、贪婪算法、禁忌搜索算法、神经网络、遗传算法以及模拟退火算法等都可以用来解决着色问题。(然而到现在我还是一个都不会)

通常解决着色问题的算法采用暴力法、贪婪法、深度优先、广度优先等思想可以优解,但显然时间复杂性太大,如回溯算法的时间复杂度为指数阶的;而Welsh-Powell算法和贪婪算法理论上都可以在多项式时间内得到可行解,然而却并不是最优解。

现在先讲一下Welsh-Powell法和贪婪法。
穷举法-Welsh-Powell着色法

  • I. 将图 G 中的结点按度数递减顺序排序(可能不唯一,结点数相同的点可能有多个)
  • II. 用第一种颜色对第一结点着色,并按排列顺序对与前面着色结点不相邻的每一结点着上相同的颜色。
  • III. 用第二种颜色对尚未着色的结点重复II,用第三种颜色继续这种做法,直到所有的结点全部着上色为止。


贪心法
贪心策略:选择一种颜色,以任意顶点作为开始顶点,依次考察图中的未被着色的各个顶点,如果一个顶点可以用颜色1着色,换言之,该顶点的邻接点都还未被着色,则用颜色1为该顶点着色;当没有顶点能以这种颜色着色时,选择颜色2和一个未被着色的顶点作为开始顶点,用第二种颜色为尽可能多的顶点着色,如果还有未着色的顶点,则选取颜色3并为尽可能多的顶点着色,依此类推。

贪婪算法实现顶点着色问题的matlab程序

在这里,我就贴一个自己的贪婪算法。

% --- 贪婪算法实现顶点着色问题 ---
clear; 
clc;

graph = [                     % 共A、B、C、D、E、F、G、H,8个点的图
%   A B C D E F G H    
    0 1 1 1 0 0 1 0;          % A
    1 0 1 1 1 0 0 0;          % B
    1 1 0 0 1 1 1 0;          % C
    1 1 0 0 1 0 1 0;          % D
    0 1 1 1 0 1 1 1;          % E
    0 0 1 0 1 0 0 1;          % F
    1 0 1 1 1 0 0 1;          % G
    0 0 0 0 1 1 1 0;          % H
    ];
vnum = max(size(graph));
colorTbl = zeros(1, vnum);    % 着色方案表,0代表未着色 

cInd = 1;
while sum(colorTbl==0) > 0                              % 全部着色完成
    for vInd = 1 : vnum
        if 0 == colorTbl(vInd)                          % 当前顶点vInd尚未着色
            tmpTbl = colorTbl(graph(:, vInd)~=0);       % 当前顶点vInd的邻接点的着色表
            if 0 == sum(tmpTbl==cInd)                   % vInd的邻接点都尚未着当前色cInd
                colorTbl(vInd) = cInd;                  % 顶点vInd着色cInd
            end
        end
    end
    cInd = cInd + 1;
end

运行以上程序,结果如下:
运行结果
也就是说点 A-E着第一种颜色,B-F-G着第二种颜色,C-D-H着第三种颜色。
结果和开篇的第二张图完全一致。
这里写图片描述

把上面代码中的图graph换成一个更复杂一点的图如下:

graph = [
%   A B C D E F G H I J    
    0 1 0 0 1 0 1 0 0 0;        % A
    1 0 1 0 0 0 0 1 0 0;        % B
    0 1 0 1 0 0 0 0 1 0;        % C
    0 0 1 0 1 0 0 0 0 1;        % D
    1 0 0 1 0 1 0 0 0 0;        % E
    0 0 0 0 1 0 0 1 1 0;        % F
    1 0 0 0 0 0 0 0 1 1;        % G
    0 1 0 0 0 1 0 0 0 1;        % H
    0 0 1 0 0 1 1 0 0 0;        % I
    0 0 0 1 0 0 1 1 0 0;        % J
    ];

这里写图片描述

程序运行结果如下:
这里写图片描述
与以上结果也完全一致。但是显然当点的规模增大后,程序的时间复杂度会呈指数级别上升。还是学会其他更优的解法好。

着色问题是指给定一个无向,每个顶点可以被染成三种颜色之一,使得相邻的顶点颜色不同。这个问题可以使用回溯法求解。 回溯法是一种通过不断地尝试所有可能的解决方案来寻找最优解的算法。在三着色问题中,我们可以从第一个顶点开始,依次尝试三种颜色,对每一种颜色都进行递归搜索,直到所有顶点都被染色或无法染色为止。 具体实现步骤如下: 1. 选择任意一个未染色顶点作为当前顶点,从三种颜色中选择一种作为当前颜色。 2. 检查当前颜色是否与相邻的已染色顶点颜色相同,如果相同则换一种颜色,直到找到一种不同的颜色为止。 3. 如果所有颜色都尝试过了还是无法找到合适的颜色,则回溯到上一个顶点,尝试其他颜色。 4. 递归搜索下一个未染色顶点,重复上述步骤,直到所有顶点都被染色或无法染色为止。 代码实现如下: ``` def three_color(graph, colors, vertex): if vertex == len(graph): return True for color in range(1, 4): if is_valid(graph, colors, vertex, color): colors[vertex] = color if three_color(graph, colors, vertex+1): return True colors[vertex] = 0 return False def is_valid(graph, colors, vertex, color): for i in range(len(graph)): if graph[vertex][i] == 1 and colors[i] == color: return False return True ``` 其中,graph表示邻接矩阵,colors表示已染色顶点,vertex表示当前未染色顶点。函数three_color返回一个布尔值,表示是否能够找到合适的染色方案。 使用该算法求解三着色问题的时间复杂度为O(3^n),其中n为顶点数。因此,该算法的效率较低,只适用于小规模的问题。在实际应用中,可以使用更高效的算法求解。
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

轻蓝雨

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值