图的着色问题

135 阅读4分钟

本文已参与「新人创作礼」活动,一起开启掘金创作之路

图的着色问题

在一个无向图中,相邻的俩个顶点的颜色不可以相同

数学定义:给定一个无向图G=(V, E),其中V为顶点集合,E为边集合,图着色问题即为将V分为K个颜色组,每个组形成一个独立集,即其中没有相邻的顶点。其优化版本是希望获得最小的K值。

问题域

  1. 图的m-着色判定问题——给定无向连通图G和m种不同的颜色。用这些颜色为图G的各顶点着色,每个顶点着一种颜色,是否有一种着色法使G中任意相邻的2个顶点着不同颜色?
  2. 图的m-着色优化问题——若一个图最少需要m种颜色才能使图中任意相邻的2个顶点着不同颜色,则称这个数m为该图的色数。求一个图的最小色数m的问题称为m-着色优化问题。

解决方案

1.图的m-着色判定问题

用户输入格式:输入顶点数、颜色数、和边数,还有无向图中有有相连边的顶点。

输入顶点数、颜色数和边数均为整数,若输入不符合格式,则提示用户重新输入。

主函数main代码如下:

n为顶点数,m为图的颜色数,edge为图的边数,以及核心函数graphcolor

 int main()
 {
     int n, m, edge;
     int i, j;
     //输入顶点数为整数,否则一直循环
     printf("----------图的顶点数、颜色和边数最大为200----------\n");
     while (1)
     {
         printf("请输入图的顶点数:\n");
         int num = scanf("%d", &n);
         if (num < 0)
         {
             printf("Warning!<请输入格式正确的整数>\n");
         }
         if (n < 0 || n > 200)
         {
             printf("Warning!<请输入大于等于0且小于200的整数>\n");
         }
         else
             break;
         cin.sync();
     }
     //输入图的颜色数为整数,否则一直循环
     while (1)
     {
         printf("请输入图的颜色数:\n");
         int num = scanf("%d", &m);
         if (num < 0)
         {
             printf("Warning!<请输入格式正确的整数>\n");
         }
         if (m < 0 || m > 200)
         {
             printf("Warning!<请输入大于等于0且小于200的整数>\n");
         }
         else
             break;
         cin.sync();
     }
     //输入无向图的边数为整数,否则一直循环
     while (1)
     {
         printf("请输入图的边数:\n");
         int num = scanf("%d", &edge);
         if (num < 0)
         {
             printf("Warning!<请输入格式正确的整数>\n");
         }
         if (edge < 0 || edge > 200)
         {
             printf("Warning!<请输入大于等于0且小于200的整数>\n");
         }
         else
             break;
         cin.sync();
     }
     (edge > 0) ? printf("%请输入邻接矩阵,即输入有边相连的俩个顶点,如顶点1和顶点2有相连的边,则输入1 2:\n") : 1;
     for (int k = 0; k < edge; k++)
     {
         while (1)
         {
             int num = scanf("%d%d", &i, &j);
             if(num < 2)
                 printf("请输入正确格式的整数\n");
             else if(i<=0 || i >200 || j <=0 || j>200)
                 printf("请输入规定范围内的整数\n");
             else 
                 break;
             cin.sync();
         }
         edges[j][i] = edges[i][j] = 1;
     }
     (graphcolor(n, m)) ? 1 : printf("该情况下无解");
     return 0;
 }

核心函数graphcolor代码如下

 bool graphcolor(int n, int m)
 {
     bool flag = false;
     int k = 1;
     int count = 0;
     while (k >= 1)
     {
         color[k] = color[k] + 1;
         while (color[k] <= m)
             if (judge(k))
             {
                 break;
             }
             else
             {
                 color[k] = color[k] + 1;
             }
         if (color[k] <= m && k == n)
         {
             flag = true;
             count++;
             printf("--%d种解法为--\n", count);
             for (int i = 1; i <= n; i++)
             {
                 printf("%d--%d\n", i, color[i]);
             }
             printf("-------------\n");
         }
         else if (color[k] <= m && k < n)
         {
             k++;
         }
         else
         {
             color[k] = 0;
             k--;
         }
     }
     return flag;
 }

判断是否出现相邻顶点颜色一样的函数judge代码如下:

 bool judge(int k)
 {
     for (int i = 1; i < k; i++)
     {
         if (edges[k][i] == 1 && color[i] == color[k])
             return false;
     }
     return true;
 }

现在解释大概思路,graphcolor函数形参n,m分别代表顶点数和边数

设置一个涂色方案数组color,数组中初始值全为0,flag变量记录是否有解,如果有解,则函数返回true,无解函数返回false,变量k用来控制涂色的顶点,变量count用来记录解法。

从第一个顶点1开始,陆续给顶点安排颜色号,每一个顶点均从1开始,若涂上当前颜色号judge返回false,则安排下一个颜色号,重新判断,直到judge返回true,也就是无相邻边的颜色相同。

(1)当当前顶点为涂完色的顶点,且顶点号仍在范围内的时候,有解法,输出顶点涂的颜色号。

(2)当当前顶点不是最后一个涂完色的顶点,即还存在未涂颜色的顶点时,k++,即进行下一个顶点的涂色工作。

(3)如果不是上述俩种情况,则剩余的情况为1)若当前顶点涂的颜色超过规定颜色数,这个时候需要将该顶点颜色号置为0,并回溯到上一个顶点,让上一个顶点的颜色号找到下一个可以涂的颜色,再次判断当前顶点是否能有解,如果上一个顶点无法找到让当前顶点有解的解法,继续回溯,若回溯到第一个顶点,仍没有有解的解法,则当前情况无解。2)当前顶点为最后一个顶点,已经输出完最后一个顶点能涂颜色的解数,需要回溯到上一个顶点,让上一个顶点找到下一个能涂的颜色,继续输出其他符合条件的解。

\