圖的m着色問題

圖的m着色問題算法

一:問題描述數組

給定無向連通圖G=VE)和m種不一樣的顏色。用這些顏色爲圖G的各頂點着色,每一個頂點着一種顏色。若是有一種着色法使G中有邊相連的兩個頂點着不一樣的顏色,則稱這個圖是m可着色的。圖的m着色問題是對於給定圖Gm中顏色,找出全部不一樣的着色方法。數據結構

 

二:問題分析框架

該問題中每一個頂點所着的顏色均有m中選擇,n個頂點所着顏色的一個組合是一個可能的解。根據回溯法的算法框架,定義問題的解空間及其組織結構是很容易的。從給定的已知條件看,無向連通圖G中假設有n個頂點,它確定至少有n-1條邊,有邊相連的兩個頂點所着顏色不相同,n個頂點所着顏色的全部組合中必然存在不是問題着色方案的組合,所以須要設置約束條件;而針對全部可行解(組合),不存在可行解的優劣問題。因此不須要設置限界條件。函數

 

三:算法設計spa

I.定義數據結構設計

 定義問題的解空間爲數組x[]code

‚ 定義無向連通圖的存儲空間和形式,爲二維數組a[][]blog

ƒ定義數組b[3]b[0]存儲無向連通圖的節點個數,b[1]存儲無向連通圖的邊數,b[2]存放着色方案的個數。io

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("請輸入無向連通圖的節點數:\n");
 9     scanf("%d",&q);
10     b[0]=q;
11     printf("請輸入無向連通圖的邊數:\n");
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("無向連通圖矩陣形式:\n");
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("\n");
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種着色方案:\n",b[2]);
51         for(int i=1;i<=b[0];i++)
52         {
53             printf("%4d",x[i]);
54         }
55         printf("\n");
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種着色方案:\n",b[2]);
        for(int i=1;i<=b[0];i++)
        {
            printf("%4d",x[i]);
        }
        printf("\n");
    }
    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爲不一樣值時所需的着色狀況。

相關文章
相關標籤/搜索