图的m着色问题

图的m着色问题

一:问题描述

给定无向连通图G=VE)和m种不同的颜色。用这些颜色为图G的各顶点着色,每个顶点着一种颜色。如果有一种着色法使G中有边相连的两个顶点着不同的颜色,则称这个图是m可着色的。图的m着色问题是对于给定图Gm中颜色,找出所有不同的着色方法。

 

二:问题分析

该问题中每个顶点所着的颜色均有m中选择,n个顶点所着颜色的一个组合是一个可能的解。根据回溯法的算法框架,定义问题的解空间及其组织结构是很容易的。从给定的已知条件看,无向连通图G中假设有n个顶点,它肯定至少有n-1条边,有边相连的两个顶点所着颜色不相同,n个顶点所着颜色的所有组合中必然存在不是问题着色方案的组合,因此需要设置约束条件;而针对所有可行解(组合),不存在可行解的优劣问题。所以不需要设置限界条件。

 

三:算法设计

I.定义数据结构

 定义问题的解空间为数组x[]

‚ 定义无向连通图的存储空间和形式,为二维数组a[][]

ƒ定义数组b[3]b[0]存储无向连通图的节点个数,b[1]存储无向连通图的边数,b[2]存放着色方案的个数。

II.确定解空间的组织结构

   问题的解空间组织结构是一颗满m叉树,树的深度为n(n指连通图结点数

III.搜索解空间

IV.设置约束条件

题中条件为,当前顶点要与前面已经确定颜色且有边相连的顶点的颜色不相同。假设当前扩展结点所在的层次为t,则下一步扩展就是要判断第t个顶点着什么颜色,第t个顶点所着的颜色要与已经确定的第1-(t-1)个顶点中与其有边相连的颜色不相同。

所以,约束函数可描述为:

  int ok(int a[M][M],int x[M],int t)
  {
            for(int j=1;j<t;j++)
                if(a[t][j])
                {
  if(x[j]==x[t])
                    return 0;
                }
            return 1;
  }

V.无需设置限界条件

VI.搜索过程。拓展结点沿着某个分支拓展时需要判断约束条件,如果满足,则进入深一层次继续搜索;如果不满足,则拓展生成的结点被剪掉。搜索到叶子结点时,找到一种着色方案。搜索过程直到所有活结点变成死结点为止。

四:实例构造

如下图所示的无向连通图和m=3.

 

搜索过程:

    从根结点A开始,结点A是当前的活结点,也是当前的拓展节点,太代表的状态是给定的无向连通图中任何一个顶点都还没有着色。沿着x[1]=1分支拓展,满足约束条件,生成的结点B将成为活结点,并且成为当前的拓展结点。拓展结点B沿着x[2]=1拓展,不满足约束条件,生成的结点被剪掉,然后沿着x[2]=2,分支拓展,满足约束条件,生成的结点C成为活结点,并且成为当前的拓展结点.....等等,其他搜索依次进行,由下述程序可得最终结果,有6中着色方案,即(1   2   3   1   3)(1   3   2   1   2)(2   1   3   2   3)(2   3   1   2   1)(3   1   2   3   2)(3   2   1   3   1)

C/C++程序如下:

 1 #include<stdio.h>
 2 #define M 30
 3 //图的m着色问题
 4 void print(int a[M][M],int b[3])
 5 {
 6     int q=0,p=0,i=0,j=0,c=0,d=0;
 7     //输入
 8     printf("请输入无向连通图的节点数:
");
 9     scanf("%d",&q);
10     b[0]=q;
11     printf("请输入无向连通图的边数:
");
12     scanf("%d",&p);
13     b[1]=p;
14     for(i=0;i<p;i++)
15     {
16         printf("第%d条边的起点 终点:",i+1);
17         scanf("%d%d",&c,&d);
18         a[c][d]=1;
19         a[d][c]=1;
20     }
21     //输出
22     printf("无向连通图矩阵形式:
");
23     for(i=0;i<=q;i++)
24     {
25         for(j=0;j<=q;j++)
26         {
27             printf("%4d",a[i][j]);
28         }
29         printf("
");
30     }
31 }
32 
33 int ok(int a[M][M],int x[M],int t)
34 {
35     for(int j=1;j<t;j++)
36         if(a[t][j])
37         {    if(x[j]==x[t])
38         
39                 return 0;
40         }
41         return 1;
42 }
43 
44 void Backtrack(int t,int x[],int m,int b[3],int a[M][M])        //m种颜色
45 {
46     
47     if(t>b[0])
48     {
49         b[2]++;
50         printf("第%d种着色方案:
",b[2]);
51         for(int i=1;i<=b[0];i++)
52         {
53             printf("%4d",x[i]);
54         }
55         printf("
");
56     }
57     else
58     {
59         for(int i=1;i<=m;i++)
60         {
61             x[t]=i;
62             if(ok(a,x,t)!=0)
63                 Backtrack(t+1,x,m,b,a);
64         }
65     }
66 }
67 
68 void main()
69 {
70     int a[M][M]={0};
71     int x[M];    //解空间
72     int b[3]={0};//b[0]存放节点总数 b[1]存放边的总数
73     int m=3;            //m种颜色
74     print(a,b);
75     Backtrack(1,x,m,b,a);
76     
77 }

//************************运行结果如下**********************//

/*

请输入无向连通图的节点数:

5

请输入无向连通图的边数:

7

1条边的起点 终点:1 2

2条边的起点 终点:1 3

3条边的起点 终点:2 3

4条边的起点 终点:2 4

5条边的起点 终点:2 5

6条边的起点 终点:3 4

7条边的起点 终点:4 5

无向连通图矩阵形式:

   0   0   0   0   0   0

   0   0   1   1   0   0

   0   1   0   1   1   1

   0   1   1   0   1   0

   0   0   1   1   0   1

   0   0   1   0   1   0

1种着色方案:

   1   2   3   1   3

2种着色方案:

   1   3   2   1   2

3种着色方案:

   2   1   3   2   3

4种着色方案:

   2   3   1   2   1

5种着色方案:

   3   1   2   3   2

6种着色方案:

   3   2   1   3   1

Press any key to continue*/

 

 

五:算法描述

在算法描述中,数组x[]记录着色方案,b[]数组中元素b[2]记录着色方案的种数,初始值为0m为给定的颜色数;该算法的关键是判断当前的结点可以着那种颜色。图的m着色问题的算法描述如下:

void Backtrack(int t,int x[],int m,int b[3],int a[M][M])        //m种颜色
{
    if(t>b[0])
    {
        b[2]++;
        printf("第%d种着色方案:
",b[2]);
        for(int i=1;i<=b[0];i++)
        {
            printf("%4d",x[i]);
        }
        printf("
");
    }
    else
    {
        for(int i=1;i<=m;i++)
        {
            x[t]=i;
            if(ok(a,x,t)!=0)
                Backtrack(t+1,x,m,b,a);
        }
    }
}

从根结点开始搜索着色方案,即Backtrack(1,x,m,b,a)。

六:算法分析

计算限界函数需要O(n)时间,需要判断限界函数的结点在最坏的情况下有1+m+m^2+m^3+...+m^(n-1)=(m^n-1)/(m-1)个,故耗时O(n*m^n);在叶子结点处输出着色方案需要耗时O(n),在最坏的情况下会搜索到每一个叶子节点,叶子节点有m^n个,故耗时为O(n*m^n)。图的m的着色问题的回溯算法所需的时间为O(n*m^n)+O(n*m^n)=O(n*m^n)

七:小结

1.当所给的问题的n个元素中每一个元素均有m中选择,要求确定期中的一种选择,使得对这n个元素的选择结果向量满足某种性质,这类问题的解空间称为满m叉树。均可以用上述算法进行求解。

2.上述C/C++程序中也可改进为将m的值由用户输入,然后存入b[4]数组中的元素b[3],以方便求m为不同值时所需的着色情况。

原文地址:https://www.cnblogs.com/lzr-rr/p/3499751.html