图的着色
已知一个图G和m>0种颜色,在只准使用这m种颜色对G的结点着色的情况下,是否能使图中任何相邻的两个结点都具有不同的颜色呢?这个问题称为m-着色判定问题。在m-着色最优化问题中,则是求可对图G着色的最小整数m。称m为图G的色数。
4种颜色足以对任何地图着色,如图,对一平面图的4-着色判定问题(平面图是一个能画于平面上而边无任何交叉的图)。将地图的每个区域变成一个结点,若两个区域相邻,则相应的结点用一条边连接起来。
假定用图的邻接矩阵Graph(1:n,1:n)来表示一个图G,其中若(i,j)是G的一条边,则Graph(i,j)=true,否则Graph(i,j)=false。。颜色用整数1,2,…,m表示,解则用n-元组(X(1),…,X(n))来给出,其中X(i)是结点i的颜色。使用递归回溯表示,得到算法MColoring。此算法使用的基本状态空间树是一棵度数为m,高为n+1的树。在i级上的每一个结点有m个孩子,它们与X(i)的m种可能的赋值相对应,1≤i≤n。在n+1级上的结点都是叶结点。
找一个图的所有m-着色方案,代码如下:
void MColoring(int k) //这是图着色的一个递归回溯算法。图G用它的布尔邻接矩阵Graph(1:n,1:n) //表示。它计算并打印出符合以下要求的全部解,把整数1,2,…,m分配给图中 //各个结点且使相邻近的结点的有不同的整数。k是下一个要着色结点的下标。 int m,n,X[n];bool Graph[n][n]; // m、n、X[n]定义成全局变量 int k; while(1) { //产生对X(k)所有的合法赋值。 NextValue(k); //将一种合法的颜色分配给X[k] if(X[k]==0) { break;} //没有可用的颜色了 if(k==n) {print(X);} //至多用了m种颜色分配给n个结点 else {MColoring(k+1); //所有m-着色方案均在此反复递归调用中产生 };//while }//Mcoloring 在最初调用Mcoloring(1)之前,应对图的邻接矩阵置初值并对数组X置0值。 在确定了X(1)到X(k-1)的颜色之后,过程NextValue从这m种颜色中挑选 一种符合要求的颜色,并把它分配给X(k),若无可用的颜色,则返回X(k)=0。
这个算法的计算时间上界可以由状态空间树的内部结点数Σmi(0<i<n-1)得到。在i=0每个内部结点处,为了确定它的子结点所对应的合法着色,由NextValue所花费的时间是О(mn)。因此,总的时间由Σmin=n(mn+1-m)/(m-1)=О(n*mn)所限界。
生成下一种颜色,代码如下:
void NextValue(k) { //进入此过程前X(1),…,X(k-1)已分得了区域[l,m]中的整数且相邻近的结 //点有不同的整数。本过程在区域[0,m]中给X(k)确定一个值:如果还剩下 //一些颜色,它们与结点k邻接的结点分配的颜色不同,那末就将其中最高 //标值的颜色分配给结点k;如果没剩下可用的颜色,则置 X(k)为0。 int m,n,X[n];bool Graph[n][n];// m、n、X[n]定义成全局变量 int j,k; while(1) { X[k]=(X[k]+l) mod (m+l); //试验下一个最高标值的颜色 if(X[k]==0) { return;} //全部颜色用完 for(j=1;j<=n;++j) { //检查此颜色是否与邻近结点的颜色不同 if(Graph[k][j] and X[k]==X[j]) break; //如果(k,j)是一条边,并且邻近的结点有相同的颜色 }//for if(j==n+l) return; //找到一种新颜色 }//while //否则试着找另一种颜色// }// NextValue
下图给出了一个包含四个结点的简单图。下面是一棵由过程MColoring生成的树。到叶子结点的每一条路径表示一种至多使用3种颜色的着色法;
注意:正好用3种颜色的解只有12种。
'
技术让梦想更伟大