图的m着色问题

问题描述

给定无向连通图G和m种不同的颜色。用这些颜色为图G的各顶点着色,每个顶点着一种颜色。是否有一种着色法使G中每条边的2个顶点着不同颜色。这个问题是图的m可着色判定问题。若一个图最少需要m种颜色才能使图中每条边连接的2个顶点着不同颜色,则称这个数m为该图的色数。求一个图的色数m的问题称为图的m可着色优化问题。

image

给定图G=(V,E)和m种颜色,如果这个图不是m可着色,给出否定回答;如果这个图是m可着色的,找出所有不同的着色法。

问题分析

1> 解向量:(x1, x2, … , xn)表示顶点i所着颜色x[i]

2> 解空间树:子集树,下图为n=3,m=3时问题的解空间树

3> 剪枝函数:顶点i与已着色的相邻顶点颜色不重复。约束函数

image

算法实现

/** 
图的m着色问题
输入示例
5 8 5
1 2
1 3
1 4
2 3
2 4
2 5
3 4
4 5
*/
#include <iostream>
using namespace std;

class Color
{
	friend int mColoring(int,int,int**);
	private:
		bool ok(int k);
		void backtrack(int t);
		int n,			// 图的顶点数
			m,			// 可用颜色数 
			**a,		// 图的邻接矩阵
			*x,			// 当前解
			sum;		// 当前已找到的可m着色方案数
};

bool Color::ok(int k)
{
	// 检查颜色可用性
	for (int j=1; j<k; j++)
	{
		if ((a[k][j]==1)&&(x[j]==x[k]))
			return false;
	}
	return true;
}

/* 回溯法 子集树 */
void Color::backtrack(int t)
{
	if (t>n)	// 搜索到叶子结点
	{
		sum++;
		for (int i=1; i<=n; i++)
		{
			cout << x[i] << " ";
		}
		cout << endl;
	}
	else
	{
		for (int i=1; i<=m; i++)
		{
			x[t] = i;
			if (ok(t))
			{
				backtrack(t+1);
			}
			x[t] = 0;
		}
	}
}

int mColoring(int n, int m, int** a)
{
	Color C;
	// 初始化C
	C.n = n;
	C.m = m;
	C.a = a;
	C.sum = 0;
	int *x = new int[n+1];
	for (int i=0; i<=n; i++)
	{
		x[i] = 0;
	}
	C.x = x;
	C.backtrack(1);
	delete []x;
	return C.sum;
}

void main()
{
	int e,m,n,u,v;

    int** a = new int*[100];
    for(int k=0; k<100; k++)
	{
        a[k] = new int[100];
	}

	while(1)
	{
		cout << "输入顶点数n、边数e和着色数m:" << endl;
		cin >> n >> e >> m;
		cout << "请输入无向图的边(如边(1,2)则输入1 2):" << endl;
		for (int i=0; i<e; i++)
		{
			cin >> u >> v;
			a[u][v] = 1;
			a[v][u] = 1;
		}
		cout << "可行的着色法:" << endl;
		int sum = mColoring(n,m,a);
		cout << "总共有" << sum << "种着色法" << endl;
	}
}

程序执行结果:

wps9601.tmp

wpsB070.tmp

posted @ 2015-07-11 11:08  枯桃  阅读(2820)  评论(0编辑  收藏  举报