圖的m着色問題回溯法求解

問題描述

給定無向連通圖G和m種不同的顏色。
用這些顏色爲圖G的各頂點着色,每個頂點着一種顏色。是否有一種着色法使G中每條邊的2個頂點着不同顏色。這個問題是圖的m可着色判定問題。

若一個圖最少需要m種顏色才能使圖中每條邊連接的2個頂點着不同顏色,則稱這個數m爲該圖的色數。

求一個圖的色數m的問題稱爲圖的m可着色優化問題。
在這裏插入圖片描述
連通圖的可着色問題
給定圖G=(V,E)和m重顏色,若這個圖不是m可着色,給出否定回答,若這個圖是m可着色的,找出所有不同的着色法。

解向量:

(x1, x2, … , xn)表示頂點i所着顏色x[i] 用m種顏色爲無向圖G=(V,E)着色,其中,V的頂點個數爲n,可以用一個n元組x=(x1,x2,…,xn)來描述圖的一種可能着色,其中,xi∈{1, 2, …, m},(1≤i≤n)表示賦予頂點i的顏色。例如,5元組(1, 2, 2, 3, 1)表示對具有5個頂點的無向圖的一種着色,頂點A着顏色1,頂點B着顏色2,頂點C着顏色2,如此等等。

如果在n元組X中,所有相鄰頂點都不會着相同顏色,就稱此n元組爲可行解,否則爲無效解。若一個圖是m可着色的,要求出所有的不同着色法。

解空間

圖的m着色問題的解空間是一棵排列樹,每個頂點可着顏色有m種選擇,n個頂點就有mn種不同的着色方案,問題的解空間是一棵高度爲n的完全m叉樹,這裏樹高度的定義爲從根節點到葉子節點的路徑的長度。每個分支結點,都有m個兒子結點。最底層有mn個葉子結點。
在這裏插入圖片描述

例如,表示用3種顏色爲3個頂點的圖着色的狀態空間樹。如下圖所示,對第i(i>=1)層上的每個頂點,從其父節點到該節點的邊上的標號表示頂點i着色的顏色編號。

四色定理

四色問題是m圖着色問題的一個特例,根據四色原理,證明平面或球面上的任何地圖的所有區域都至多可用四種顏色來着色,並使任何兩個有一段公共邊界的相鄰區域沒有相同的顏色。這個問題可轉換成對一平面圖的4-着色判定問題(平面圖是一個能畫於平面上而邊無任何交叉的圖)。將地圖的每個區域變成一個結點,若兩個區域相鄰,則相應的結點用一條邊連接起來。多年來,雖然已證明用5種顏色足以對任一幅地圖着色,但是一直找不到一定要求多於4種顏色的地圖。直到1976年這個問題才由愛普爾,黑肯和考西利用電子計算機的幫助得以解決。他們證明了4種顏色足以對任何地圖着色。

洛谷OJ-P2819圖的m着色問題

輸入

第1行有3個正整數n,k 和m,表示給定的圖G有n個頂點和k條邊,m種顏色。頂點編號爲1,2,…,n。接下來的k行中,每行有2個正整數u,v,表示圖G 的一條邊(u,v)。

5 8 4
1 2
1 3
1 4
2 3
2 4
2 5
3 4
4 5

輸出

程序運行結束時,將計算出的不同的着色方案數輸出。

48

代碼

#include <iostream>
using namespace std;
#include<cstring>
#include<math.h>
int n;//圖一共有n個頂點
int m;//m種顏色被選擇
int k;//圖中有k條邊
int sum=0;//圖的m着色種類
int x[101];//存放當前的着色序列{...}
int a[101][101];//圖的鄰接矩陣
//判斷給點t着色爲x[t]是否可行
bool OK(int t)
{
	//可行的條件是當前點相鄰的點不能與之同色
    for(int i=1;i<t;i++)
        if(a[i][t]==1&&x[i]==x[t])
            return false;
	//如果所有與之相鄰的點都不與之同色
    return true;
}
void getsum(int i)
{
    if(i>n){//i>n說明找到了一個可行的塗色方案
        sum++;//塗色方案數++
        //這裏可以選擇性的輸出解向量
        //for(int k=1;k<=n;k++)
        	//cout<<x[i]<<" ";
        //cout<<endl;
        return ;
    }
    //還沒有到葉子節點,需要給當前節點可行的塗色
    else{
        for(int k=1;k<=m;k++){	//子樹是一個m叉樹
            x[i]=k;//給第i個頂點着第k種顏色
            if(OK(i))
                getsum(i+1);
            x[i]=0;//如果給第i個頂點着第k種顏色不可行
            //不塗色,便於後續塗色
        }
    }
    return ;//如果當前節點所有顏色都不可行,結束對子樹的遍歷,返回
}
int main()
{
    cin>>n>>k>>m;//輸入定點數,邊數,着色種類數
    int x,y;
    memset(a,0,sizeof(a));//給鄰接矩陣賦初值
    for(int i=1;i<=k;i++){
        cin>>x>>y;
        a[x][y]=a[y][x]=1;//生成鄰接矩陣
    }
    getsum(1);
    cout<<sum;//輸出最大可行的着色方案數,sum初始值爲0
    return 0;
}

AC

在這裏插入圖片描述

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章