回溯法——图着色问题

图着色问题

“四色问题”一直是数学方面一个重要且困难的问题,直到计算机的发明才得以侧面证明,如何求一个图的着色色数,可以通过回溯法来解决。

问题描述

已知一个图G和m种颜色,在只准使用这m种颜色对G的结点着色的情况下,是否能使图中任何相邻的两个结点都具有不同的颜色呢?这个问题称为m-着色判定问题。可对图G着色的最小正整数m,称为图G的色数。

分析设计

图的表示我们采用二维数组邻接矩阵的形式存储。颜色我们可以使用正整数1、2、3……m的形式表示,通过一位数组x[n]来记录结点颜色,x[i]表示结点i的颜色为x[i]。

我们可以通过深度遍历的方法遍历每一个结点,颜色也从1开始试,在给每个结点确定颜色时,判断与它相邻的结点是否着色冲突:

  • 都不冲突,则继续往下一个结点走;
  • 存在冲突,则换一个颜色继续试;当所有颜色试完均无可行解,则回溯至上一个顶点;
  • 当所有顶点都找到了一种颜色解决时,我们就可以说改图所需色数可能小于等于m。

源代码

#include <iostream>
#include <vector>

using namespace std;

vector<vector<bool> > graph;	//邻接图
vector<int> x;					//节点数组
int color;						//颜色种类

//输出结果
void print(int k) {
	for (int i = 1; i <= k; i++) 
		cout << x[i] << " ";
	cout << endl;
}

//递归算法
void MColoring(int k) {
	int j;
	while (1) {
		x[k]++;
		if (x[k] > color)
			return;
		for (j = 1; j <= k - 1; j++) 
			if (graph[k][j] && x[k] == x[j])	//存在冲突
				break;
		if (j == k)
			break;
	}
	if (k == x.size() - 1) {	//找到一种可能
		print(k);
		return;
	}
	else
		MColoring(k + 1);	//递归进入下一层
}


int main() {
	int n;
	cout << "输入图顶点数:";
	cin >> n;
	vector<vector<bool> >g(n + 1, vector<bool>(n + 1, false));	//邻接矩阵图
	cout << "输入邻接边a b:(输入0结束)" << endl;
	int a, b;
	while (cin >> a && a) {
		cin >> b;
		g[a][b] = true;
		g[b][a] = true;
	}
	graph = g;

	vector<int> t(n + 1, 0);
	x = t;
	x[1] = 1;

	cout << "输入颜色种类:";
	cin >> color;

	MColoring(1);

	system("pause");
	return 0;
}


/*
1 2
2 3
1 3
1 4
2 4
2 5
3 4
4 5
*/

运行结果

在这里插入图片描述
在这里插入图片描述


版权声明:本文为weixin_42182525原创文章,遵循CC 4.0 BY-SA版权协议,转载请附上原文出处链接和本声明。