• 图的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为不同值时所需的着色情况。

  • 相关阅读:
    利用智能手机(Android)追踪一块磁铁(三)
    利用智能手机(Android)追踪一块磁铁(二)
    利用智能手机(Android)追踪一块磁铁(一)
    android音频发生器
    接口的作用(java)
    Botposter.com集群ETCD2.3.7升级至3.0实录[原创]
    springboot2+jpa+hikari+oracle实战
    Nginx配置详解
    Nginx安装启动+springboot项目实现负载均衡实战
    springboot使用websocket进行实时传送信息实战(包含服务端和客户端)
  • 原文地址:https://www.cnblogs.com/lzr-rr/p/3499751.html
Copyright © 2020-2023  润新知