圖上的染色問題算是一個挺有名的NP-完全問題了吧
題目描述
給定無向連通圖G 和M 種不同的顏色,用這些顏色為圖G 的各頂點着色,每個頂點着一種顏色。如果有一種着色法使G 中每條邊的2 個頂點着不同的顏色,則稱這個圖是M 可着色的。圖的M 着色問題是對於給定圖G 和M 種顏色,找出所有不同的着色法。對於給定的無向連通圖G 和M 種不同的顏色,編程計算圖的所有不同的着色法。
輸入
第一行有3 個正整數N,K 和M,表示給定的圖G 有N 個頂點和K 條邊,M 種顏色。頂點編號為1,2……,N。接下來的K 行中,每行有2 個正整數U, V,表示圖G 的一條邊(U,V)。
數據范圍:1<N<=100 1<K<=2500 1<M<=6
輸出
不同的着色方案數
樣例輸入
5 8 4
1 2
1 3
1 4
2 3
2 4
2 5
3 4
4 5
樣例輸出
48
我的解析:
這道題是一道典型的搜索題,需要dfs和一點點優化(剪枝)。
我們來看一下樣例給的這張圖。
為什么是搜索?對於樣例來說,每個點我們都有4種顏色可以選擇,而在確定完一個點的顏色后又要選取其他點的顏色,並不能與它相連的點重復。於是馬上想到要進行搜索。
搜索的過程:對於每個點,枚舉它可能被染的顏色。如果與它相連的點顏色和它相同,那么就換下一個顏色;如果哪個顏色也不能選,那就回到上一個點換顏色(回溯)……
當確定完最后一個點的顏色后,這就是一個可行解,將答案增加1。
我們在判斷哪個點與這個點(編號為n)連接並顏色相同時,本來是要遍歷一遍圖上的點的,而這樣會超時。其實不需要這樣做。只需遍歷從編號1 到 編號n-1 的點就行了,因為
並沒有確定編號n以后的點的顏色。這樣相對於把點全遍歷一遍,能更快一點,算是一個優化吧。
我的代碼:
#include<cstdio> #include<algorithm> using namespace std; int m,n,k; int map[105][105]; int color[105]; int ans; void a(int p) { if(p == n+1) { ans++; return; } else { for(int i=1;i<=m;i++) { int mmp = false; for(int j=1;j<=p;j++) { if(map[p][j] == 1 && color[j] == i) { mmp = true; break; } } if(mmp == true) continue; color[p] = i; a(p+1); color[p] = 0; } } } int main() { // freopen("color.in","r",stdin); // freopen("color.out","w",stdout); scanf("%d%d%d",&n,&k,&m); for(int i=1;i<=k;i++) { int d1,d2; scanf("%d%d",&d1,&d2); map[d1][d2] = 1; map[d2][d1] = 1; } a(1); printf("%d",ans); return 0; }