四色标记算法

著名的四色定理说到,“如果在平面上划出一些邻接的有限区域,那么可以用四种颜色来给这些区域染色,使得每两个邻接区域染的颜色都不一样”

另一个通俗的说法是,“任意一个无飞地的地图都可以用四种颜色染色,使得没有两个相邻国家染的颜色相同。”

定理的证明比较复杂,但可以确信:四种颜色是足够染完平面图,并且保证每两个邻接区域染的颜色都不一样。

在我的研究工作中,需要实现一个这样的算法,最初我用DFS实现,确信思路正确,也测试了几组数据,然而在区域数较多的时候,由于堆栈深度过深,导致程序崩溃(我猜想是这个原因),所以后来尝试用了非递归实现的方法。

图像处理中的四色标记问题可以定义为:

给定邻接矩阵 Adj[n][n],其中若第i个区域与第j个区域相邻,则A[i][j]=1,否则A[i][j]=0,求四色标记该区域的一组解(注意:解空间可能达到4^n,故只求一组解)

/* *************************************
 *           Main Function
 *  Para:
 *      @Adj: Adjacent Matrix
 *      @Record: Record the labeled results
 *      @num: The number of regions
 *
 * *************************************/
void FourColorLabel(int ** Adj, int * Record, int num)
{
    // 染色第一个区域,先设置为1
    Record[0]=1;
    int m=1, n=1; // m计数,n为颜色值
    // 一直染色,直到染完
    while (m<=num)
    {
        while(n<=4&& m<=num)
        {
            int k=0;
            for (k=0; k<m; k++)
            {
                if (Adj[m][k]==1 && Record[k]==n) break; // 染色有冲突
            }
            if (k<m) n++;  // 染色有冲突,换新颜色
            else // 当前染色OK
            {
                Record[m]=n;
                m++;
                n=1;
            }
        }
         if (n>4) // 如果当前用的已经超出标记范围(说明在已标记的情况下,目前区域无合适的颜色,必须回退)
        {
            m--;
            n=Record[m]+1;
        }
    }
}

 以上的复杂度其实不是很好估计,跟具体的图有关,回退次数不多的情况下,很快就能完成所有染色,否则,需要更多的回退次数。 

 附上我之前用DFS染色的程序示例:

  1 #include <iostream>
  2 
  3 using namespace std;
  4 
  5 /* *************************************
  6  *
  7  *            Four Color Label
  8  *
  9  * *************************************/
 10 
 11 /* *************************************
 12  *           Main Function
 13  *  Para:
 14  *      @Adj: Adjacent Matrix
 15  *      @Record: Record the labeled results
 16  *      @cur: current index
 17  *      @n: The number of regions
 18  *
 19  * *************************************/
 20 void FourColorLabel(int Adj[][7], int* Record, int cur, int n);
 21 
 22 /* *************************************
 23  *           CheckOk
 24  *  Para:
 25  *      @Adj: Adjacent Matrix
 26  *      @Record: Record the labeled results
 27  *      @cur: current index
 28  *      @clabel: The label of cur
 29  *
 30  * Check "color the cur region with clabel" is ok or not
 31  * *************************************/
 32 bool CheckOk(int Adj[][7], int *Record, int cur, int clabel);
 33 
 34 int main()
 35 {
 36 
 37 
 38     /* ****************************************************
 39      *
 40      *     Test CASE
 41      *
 42      *     ----------------------
 43      *     | 1   /   2  /       |
 44      *     |    /-------/   3   |
 45      *     |---/        -------|
 46      *     |     4       /      |
 47      *     |------------/  5    |
 48      *     |             ------|
 49      *     |    6        /      |
 50      *     |            /    7  |
 51      *     ----------------------
 52      * ****************************************************/
 53     int Adj[7][7] = { {0, 1, 0, 1, 0, 0, 0},
 54                       {1, 0, 1, 1, 0, 0, 0},
 55                       {0, 1, 0, 1, 1, 0, 0},
 56                       {1, 1, 1, 0, 1, 1, 0},
 57                       {0, 0, 1, 1, 0, 1, 1},
 58                       {0, 0, 0, 1, 1, 0, 1},
 59                       {0, 0, 0, 0, 1, 1, 0} };
 60 
 61 
 62     int Record[7] = {0};
 63 
 64     FourColorLabel(Adj, Record, 0, 7);
 65 
 66     for(int i=0; i < 7; i++)
 67     {
 68         cout << Record[i] << " ";
 69     }
 70     cout << endl;
 71 
 72     return 0;
 73 }
 74 void FourColorLabel(int Adj[][7], int* Record, int cur, int n)
 75 {
 76     // Index exceed, then return
 77     if(cur<0 || cur >= n)
 78     {
 79         // Break Out
 80         return;
 81     }
 82     int clabel=0;
 83     if(Record[cur] != 0)
 84     {
 85         int flag = 0;
 86         for(clabel = Record[cur]+1; clabel <= 4; clabel++)
 87         {
 88             if(CheckOk(Adj, Record, cur, clabel))
 89             {
 90                 Record[cur] = clabel;
 91                 flag = 1;
 92                 break;
 93             }
 94         }
 95         // IF 成功标记
 96         if(flag == 1)
 97         {
 98             FourColorLabel(Adj, Record, cur+1, n);
 99         }
100         // ELSE 不成功,返回上一步
101         else
102         {
103             FourColorLabel(Adj, Record, cur-1, n);
104         }
105     }
106 
107 
108     int flag = 0;
109     for(clabel = 1; clabel <= 4; clabel++)
110     {
111         if(CheckOk(Adj, Record, cur, clabel))
112         {
113             Record[cur] = clabel;
114             flag = 1;
115             break;
116         }
117     }
118     // IF 成功标记
119     if(flag == 1)
120     {
121         FourColorLabel(Adj, Record, cur+1, n);
122     }
123     // ELSE 不成功,返回上一步
124     else
125     {
126         FourColorLabel(Adj, Record, cur-1, n);
127     }
128 
129 }
130 
131 bool CheckOk(int Adj[][7], int* Record, int cur, int clabel)
132 {
133     int i = 0;
134     for(;i < cur; i++)
135     {
136         // IF 相邻 && 标记相同
137         if(Adj[i][cur]==1 && Record[i]==clabel)
138         {
139             return false;
140         }
141     }
142     return true;
143 }
原文地址:https://www.cnblogs.com/moondark/p/3594188.html