首页 > 代码库 > 区域着色问题编码

区域着色问题编码

图着色问题(Graph Coloring Problem, GCP) 又称着色问题,是最著名的NP-完全问题之一。这就是我今天要和大家分析的内容。

通俗易懂的说,就是:有一张图分为N个区域,给你K种颜色,让你为每个区域着色,要求最终满足相邻区域的颜色不相同。

 

首先,在编程实现里面应该怎么来表达这张有N个区域的图呢?(借用我以前写过的一道作业题,假设有6个区域),我们可以用一个二维数组来存储每个区域两两之间的邻接关系,如下:解释一下就是说,用数组a[6][6]来表示这个6*6的二维数组,那么a[3][4]就表示区域3和区域4的关系,若a[3][4]==1,就证明这两个区域相邻,否则就是不相邻的。

技术分享

 

接下来,我们用代码来实现这6个区域的上色问题。(假设给定了4种不同的颜色,也可以用一个一维数组如b[4]来表示哈~~)

  1 #include<stdio.h>
  2 #include<stdlib.h>
  3 #define StackSize 100
  4 #define AddSize 10
  5 #define COLUMN 6
  6 
  7 typedef struct
  8 {
  9     int* top;
 10     int* base;
 11     int stacksize;
 12 }Stack;
 13 
 14 int R[COLUMN][COLUMN];
 15 
 16 void read(int *p);
 17 void Initstack(Stack *p);//构建空栈
 18 bool judgeColor(Stack *p,int m,int j);//上色法,判断能否用第j种颜色,j<=3;
 19 void Push(Stack *p, char j);//第j种颜色入栈
 20 void Pop(Stack *p,int *w);//出栈
 21 void draw(Stack P);//画图
 22 
 23 void main()
 24 {    
 25     read(R[0]);
 26     Stack P;
 27     Initstack(&P);
 28     int m = 0,j;
 29     while (m <= 5)
 30     {
 31         for (j = 0; j <= 3; j++)//第j种颜色尝试
 32         {
 33             if (judgeColor(&P,m,j))
 34             {
 35                 Push(&P, j);
 36                 break;
 37             }
 38         }
 39         while(j==4)//未能成功上色
 40         {
 41             --m;//返回上一个区域
 42             if (m < 0)//退栈退到第0块区域之前,没区域了,即不能成功为这6个区域上色
 43             {
 44                 printf("NO Solution!");
 45                 return;
 46             }
 47 
 48             int w;//上一区域颜色
 49             Pop(&P, &w);//退栈            
 50             for (j = w + 1; j <= 3; j++)
 51             {
 52                 if (judgeColor(&P,m,j))//能上此色
 53                     Push(&P, j);
 54             }
 55         }
 56         m++;//给下一区域上色
 57     }
 58     printf("OK.\n");
 59     
 60     for (int t = 0; t < 6; t++)
 61     {
 62         printf("区域%d上色为%d\n", t, P.base[t]);//指针取下标可以表示数组
 63     }
 64     
 65     return;
 66 }
 67 
 68 void read(int *p)
 69 {
 70     FILE * fp = fopen("../relation_table.txt", "r");
 71     if (!fp) exit;
 72     for (int i=0;i<6;i++)
 73     {
 74         for (int j = 0; j < 6; j++)
 75         {
 76             fscanf(fp, "%d", p++);
 77         }
 78     }
 79     fclose(fp);
 80 }
 81 
 82 void Initstack(Stack *p)//构建空栈
 83 {
 84     p->base= (int *)malloc(sizeof(int)*StackSize);
 85     if (!p->base) exit;
 86     p->top = p->base;
 87     p->stacksize = StackSize;
 88     return;
 89 }
 90 
 91 void Push(Stack *p, char j)//第j种颜色入栈
 92 {
 93     if (p->top - p->base == p->stacksize)//栈满
 94     {
 95         p->base = (int *)realloc(p->base,( p->stacksize + AddSize)*sizeof(int));
 96         if (!p->base) exit;
 97         p->top = p->base + p->stacksize;
 98         p->stacksize += AddSize;
 99     }
100     *(p->top++) = j;
101     return;
102 }
103 
104 void Pop(Stack *p, int *w)//出栈
105 {
106     if (p->base == p->top) exit;
107     *w = *(--p->top);
108     return;
109 }
110 
111 bool judgeColor(Stack * P,int m,int j)//判断第m个区域能否用第j种颜色
112 {    
113     for (int i=0; i<m&&m>0; i++)
114     {
115         if (R[i][m] == 1)//第i个区域与m区域相邻
116         {
117             if (*(P->base + i) == j)//j颜色被用过了
118                 return false;
119         }
120     }
121     return true;
122 }


我们来看看最终的结果,见证奇迹的时刻到了!

技术分享

当然,你也可以修改上面的参数,来解决更多区域更多颜色的上色问题!

区域着色问题编码