给定无向连通图G和m种不同的颜色。用这些颜色为图G的各顶点着色,每个顶点着一种颜色。是否有一种着色法使G中每条边的2个顶点着不同颜色。这个问题是图的m可着色判定问题。若一个图最少需要m种颜色才能使图中每条边连接的2个顶点着不同颜色,则称这个数m为该图的色数。求一个图的色数m的问题称为图的m可着色优化问题。
给定图G=(V,E)和m种颜色,如果这个图不是m可着色,给出否定回答;如果这个图是m可着色的,找出所有不同的着色法。
1> 解向量:(x1, x2, … , xn)表示顶点i所着颜色x[i]
2> 解空间树:子集树,下图为n=3,m=3时问题的解空间树
3> 剪枝函数:顶点i与已着色的相邻顶点颜色不重复。约束函数
/**
图的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;
}
}
原文:http://www.cnblogs.com/xwz0528/p/4638225.html