图着色问题

图着色问题

1. 问题概述

图着色问题,是最著名的 NP-完全问题之一。道路着色问题是图论中最著名的猜想之一。

  • 数学定义:

给定一个无向图 G=(V, E),其中 V 为顶点集合,E 为边集合,图着色问题即为将 V 分为 K 个颜色组,每个组形成一个独立集,即其中没有相邻的顶点。其优化版本是希望获得最小的 K 值。

  • 问题描述:

图的 m-着色判定问题——给定无向连通图 G 和 m 种不同的颜色。用这些颜色为图 G 的各顶点着色,每个顶点着一种颜色,是否有一种着色法使 G 中任意相邻的 2 个顶点着不同颜色?

图的 m-着色优化问题——若一个图最少需要 m 种颜色才能使图中任意相邻的 2 个顶点着不同颜色,则称这个数 m 为该图的色数。求一个图的最小色数 m 的问题称为 m-着色优化问题。

如图中所示,把每一个矩形收缩为一个顶点,把相邻的两个矩形用一条边相连接,就可以把一个矩形抽象为一个平面图

例: 图左)所示的矩形图可抽象为图(右) 所表示的平面图。矩形区域用数字表示,颜色用图中的各个颜色表示,则图中表示了不同矩形区域的不同着色问题。

2. 算法思想

  1. 我们可以遍历图的每一个顶点,并对当前顶点开始着色;
  2. 着色时需要保证该顶点的颜色与相邻顶点的颜色不相同;
  3. 如果相同了需要用其他颜色进行着色;
  4. 当最后一个顶点着色完成时,则已经求出一种着色方案了,输出着色方案即可;
  5. 如果当前着色的不是最后一个顶点,则继续对下一个顶点进行着色即可;

3. 求解过程

举例:用  黄  绿 红  四种颜色对 图 着色。

第一步:

  1. 对顶点 1 涂黄色,并判断改颜色与相邻的顶点的颜色是否相同;
  2. 此时顶点 1 的颜色与相邻顶点的颜色不相同,因此继续对下一个顶点进行着色即可;

第二步:

  1. 对顶点 2 涂黄色,并判断改颜色与相邻的顶点的颜色是否相同;
  2. 此时顶点 2 的颜色与相邻顶点的颜色相同,因此继续对顶点 2 着色,如绿色;
  3. 此时顶点 2 的颜色与相邻顶点的颜色不相同,因此继续对下一个顶点进行着色即可;

 第三步:

  1. 对顶点 3 涂黄色,并判断改颜色与相邻的顶点的颜色是否相同;
  2. 此时顶点 3 的颜色与相邻顶点的颜色相同,因此继续对顶点 3 着色,如绿色;
  3. 此时顶点 3 的颜色与相邻顶点的颜色相同,因此继续对顶点 3 着色,如紫色;
  4. 此时顶点 3 的颜色与相邻顶点的颜色不相同,因此继续对下一个顶点进行着色即可;

第四步:

  1. 对顶点 4 涂黄色,并判断改颜色与相邻的顶点的颜色是否相同;
  2. 此时顶点 4 的颜色与相邻顶点的颜色相同,因此继续对顶点 4 着色,如绿色;
  3. 此时顶点 4 的颜色与相邻顶点的颜色相同,因此继续对顶点 4 着色,如紫色;
  4. 此时顶点 4 的颜色与相邻顶点的颜色相同,因此继续对顶点 4 着色,如红色;
  5. 此时顶点 4 的颜色与相邻顶点的颜色不相同,因此继续对下一个顶点进行着色即可;

第五步:

  1. 对顶点 5 涂黄色,并判断改颜色与相邻的顶点的颜色是否相同;
  2. 此时顶点 5 的颜色与相邻顶点的颜色不相同;
  3. 此时对最后一个顶点着完色了,输出着色方案;

 最终着色方案为: 顶点 1 和顶点 5 是黄色,顶点 2,顶点 3,顶点 4 分别为绿色,紫色,红色。

4. 算法具体步骤

  1. 输入顶点数和着色数并存到变量 n,m 中;
  2. 输入无向图的邻接矩阵,并用二维数组进行存储;
  3. 开始着色;
  4. 循环每一个顶点,循环变量为 k;
  5. 对顶点 k 着一种颜色;
  6. 判断顶点 k 的颜色与其相邻顶点的颜色是否相同,如果相同则着另一种颜色后继续判断是否与其 1. 相邻顶点的颜色相同;
  7. 如果当前着色的是最后一个顶点,则表示已经完成了着色,输出着色方案;
  8. 如果不是最后一个顶点则表示还没对所有的顶点着完色,此时对下一个顶点进行着色即可;

完整代码:

#include <stdio.h>

int color[100];
bool ok(int k,int c[][100]) { //判断顶点k的着色是否发生冲突
	int i,j;
	for(i = 1; i < k; i++) {
		if(c[k][i]==1 && color[i] == color[k]) // 数组中为1,并且颜色与已有的颜色相同
			return false;
	}
	return true;
}
// n:顶点数,m:着色数,c:图的邻接矩阵
void graphcolor(int n,int m, int c[][100]) {
	int i, k;
	for(i = 1; i <= n; i++)
		color[i] = 0; // 颜色数组初始化为0
	k = 1; // 循环变量,表示数组的第k行
	while(k >= 1) {
		color[k] = color[k] + 1; // 顶点k颜色标记 + 1
		while(color[k] <= m) // 是否用完了可用的颜色
			if(ok(k,c)) //判断顶点k的着色是否发生冲突
				break;
			else
				color[k] = color[k] + 1;//搜索下一个颜色
		if(color[k] <= m && k == n) { // 颜色没有用完并且处理完了最后一个顶点
			for(i = 1; i <= n; i++) // 开始打印颜色方案
				printf("%d",color[i]);
			printf("\n");
		} else if(color[k] <= m && k < n) // 颜色没有用完并且当前处理的不是最后一个顶点
			k = k + 1; //处理下一个顶点
		else {
			color[k] = 0;
			k = k - 1;//回溯
		}
	}
}

int main() {
	int i, j, n, m;
	int c[100][100]; //存储n个顶点的无向图的数组
	printf("输入顶点数n和着色数m:\n"); // n:顶点数,m:着色数
	scanf("%d%d", &n, &m);
	printf("输入无向图的邻接矩阵:\n");
	for(i = 1; i <= n; i++)
		for(j = 1; j <= n; j++)
			scanf("%d", &c[i][j]);
	printf("着色所有可能的解:\n");
	graphcolor(n, m, c);

}

5. 性能分析

时间复杂度: 现分析只求出一种着色方案时的时间复杂度,假如图的顶点数为 n,代码中:判断是否颜色冲突的函数的时间复杂度为 O(n);着色函数中对 n 个顶点进行遍历,因此时间代价为 O(n);因此整个程序需要求出一种着色方案时的时间代价为 O(n2);

空间复杂度: 用一个整型二维数组存储了无向图的邻接矩阵,因此空间代价为 O(n2);

参考资料

[1] 图着色问题,https://baike.baidu.com/item/图着色问题/8928655, 2022 年 4 月

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

打赏作者

AI麥爾

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

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

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

打赏作者

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

抵扣说明:

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

余额充值