zoukankan      html  css  js  c++  java
  • 图的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为不同值时所需的着色情况。

  • 相关阅读:
    HDU 1010 Tempter of the Bone(DFS剪枝)
    HDU 1013 Digital Roots(九余数定理)
    HDU 2680 Choose the best route(反向建图最短路)
    HDU 1596 find the safest road(最短路)
    HDU 2072 单词数
    HDU 3790 最短路径问题 (dijkstra)
    HDU 1018 Big Number
    HDU 1042 N!
    NYOJ 117 求逆序数 (树状数组)
    20.QT文本文件读写
  • 原文地址:https://www.cnblogs.com/lzr-rr/p/3499751.html
Copyright © 2011-2022 走看看