【问题描述】
给定无向连通图G=(V, E)和m种不同的颜色,用这些颜色为图G的各顶点着色,每个顶点着一种颜色。是否有一种着色法使G中相邻的两个顶点有不同的颜色?
这个问题是图的m可着色判定问题。若一个图最少需要m种颜色才能使图中每条边连接的两个顶点着不同颜色,则称这个数m为该图的色数。求一个图的色数m的问题称为图的m可着色优化问题。
编程计算:给定图G=(V, E)和m种不同的颜色,找出所有不同的着色法和着色总数。
输入
第一行是顶点的个数n(2≤n≤10),颜色数m(1≤m≤n)。
接下来是顶点之间的相互关系:a b
表示a和b相邻。当a,b同时为0时表示输入结束。
输出
输出所有的着色方案,表示某个顶点涂某种颜色号,每个数字的后面有一个空格。
最后一行是着色方案总数。
【算法分析】
对m种颜色编号为1,2,…,m,由于每个顶点可从m种颜色中选择一种颜色着色,如果无向连通图G=(V, E)的顶点数为n,则解空间的大小为m的n次方种,解空间是非常庞大的,它是一棵m叉树。
当n=3,m=3时的解空间树:
图的m着色问题的约束函数是相邻的两个顶点需要着不同的颜色,但是没有限界函数。
假设无向连通图G=(V, E)的邻接矩阵为a,如果顶点i和j之间有边,则a[i][j]=1,否则a[i][j]=0。
设问题的解向量为X (x1, x2 , …, xm) ,其中xi∈{1, 2, …, m},表示顶点i所着的颜色是x[i],
即解空间的每个结点都有m个儿子。
【代码部分】
//图的m着色问题回溯算法的数据结构
#define NUM 100
int n; //图的顶点数量
int m; //可用颜色数量
int a[NUM][NUM]; //图的邻接矩阵
int x[NUM]; //当前的解向量
int sum ; //已经找到的可m着色的方案数量
//图的m着色问题回溯算法的实现
//形参t是回溯的深度,从1开始
void BackTrack(int t )
{
int i;
//到达叶子结点,获得一个着色方案
if( t > n )
{
sum ++ ;
for(i=1; i<=n ;i++)
printf("%d ",x[i]);
printf("\n");
}
else
//搜索当前扩展结点的m个孩子
for(i=1; i<=m; i++ )
{
x[t] = i;
if( Same(t) ) BackTrack(t+1);
x[t] = 0;
}
}
//检查相邻结点的着色是否一样的约束函数
//形参t是回溯的深度
bool Same(int t)
{
int i;
for(i=1; i<=n; i++ )
if( (a[t][i] == 1) && (x[i] == x[t]))
return false;
return true;
}
#include <iostream>
#include<bits/stdc++.h>
#define N 100
#define INF 0x3f3f3f3f
#define IOS ios::sync_with_stdio(false);cin.tie(0);cout.tie(0)
#define rep(i,a,n) for(int i=a;i<=n;i++)
typedef long long ll;
using namespace std;
#define NUM 100
int n;//图的顶点数量
int m;//可用颜色数量
int a[NUM][NUM];//图的邻接矩阵
int x[NUM];//当前的解向量
int sum ;//已经找到的可m着色的方案数量
bool Same(int t)//约束函数
{
int i;
for(i=1;i<=n;i++)
{
if((a[t][i]==1)&&(x[i]==x[t]))//这一行,相邻的
return false;
}
return true;
}
void Backtrack(int t)//搜索t层结点
{
int i;
if(t>n)
{
sum++;
for(i=1;i<=n;i++)
{
cout<<x[i]<<" ";
}
cout<<endl;
}
else
{
for(i=1;i<=m;i++)
{
x[t]=i;//颜色值
if(Same(t))Backtrack(t+1);
x[t]=0;//恢复
}
}
}
int main()
{
cin>>n>>m;
int i,j;
while(cin>>i>>j&&i&&j)
{
a[i][j]=a[j][i]=1;
}
Backtrack(1);
cout<<sum<<endl;
}