回溯法之圖的m著色問題
阿新 • • 發佈:2020-12-12
回溯法之圖的m著色問題
1. 問題描述
給定無向連通圖\(G\)和\(m\)種不同的顏色。用這些顏色為圖\(G\)的各個頂點著色,每個頂點著一種顏色。是否有一種著色發使\(G\)中每條邊的2個頂點著不同顏色。這個問題是圖的\(m\)可著色判定問題。若一個圖最少需要\(m\)種顏色才能使圖中每條邊連結的2個頂點著不同顏色,則稱這個數\(m\)為該圖的色數。求一個圖的色數\(m\)的問題稱為圖的\(m\)可著色優化問題。
2.問題分析
本問題只探討對於給定的\(m\),求解其可\(m\)著色的方案數
解向量:\((x_1, x_2, ..., x_n)\)表示頂點\(i\)所著顏色\(x_i\)
可行性約束函式:頂點\(i\)與已著色的相鄰頂點顏色不重複
3.程式碼求解
使用變數:
/** * n 國家數 * m 可用顏色數 * a 圖的鄰接矩陣 * x 當前解 * sum 著色方案數 **/ int n = MAX; int 0m; int a[MAX + 1][MAX + 1] = { {0, 0, 0, 0, 0, 0}, {0, 0, 1, 1, 1, 0}, {0, 1, 0, 1, 1, 1}, {0, 1, 1, 0, 1, 0}, {0, 1, 1, 1, 0, 1}, {0, 0, 1, 0, 1, 0} }; int x[MAX + 1]; long sum = 0;
核心程式碼:
// ok約束函式 // 要求a[k][j] == 1即倆頂點相鄰 // x[j] == x[k]即二者的顏色重複 // 當二者都滿足時,即該節點不符合剪枝函式,剪去 int ok(int k) { for (int j = 1; j < k; j++) if (a[k][j] && (x[j] == x[k])) return 0; return 1; } // t > n代表一種著色方案通過 // 通過遍歷m,對各個結點設定不同的顏色 // 然後通過剪枝函式,只留下相鄰頂點顏色不重複的分支,繼續遞迴求解 void BackTrack(int t) { if (t > n) sum++; else for (int i = 1; i <= m; i++) { x[t] = i; if (ok(t)) BackTrack(t + 1); } }
4. 完整程式碼
/**
* 回溯法之圖的n著色問題
**/
#include <stdio.h>
#include <stdlib.h>
#define MAX 5
/**
* n 國家數
* m 可用顏色數
* a 圖的鄰接矩陣
* x 當前解
* sum 著色方案數
**/
int n = MAX;
int m;
int a[MAX + 1][MAX + 1] = {
{0, 0, 0, 0, 0, 0},
{0, 0, 1, 1, 1, 0},
{0, 1, 0, 1, 1, 1},
{0, 1, 1, 0, 1, 0},
{0, 1, 1, 1, 0, 1},
{0, 0, 1, 0, 1, 0}
};
int x[MAX + 1];
long sum = 0;
// ok約束函式
// 要求a[k][j] == 1即倆頂點相鄰
// x[j] == x[k]即二者的顏色重複
// 當二者都滿足時,即該節點不符合剪枝函式,剪去
int ok(int k) {
for (int j = 1; j < k; j++)
if (a[k][j] && (x[j] == x[k]))
return 0;
return 1;
}
// t > n代表一種著色方案通過
// 通過遍歷m,對各個結點設定不同的顏色
// 然後通過剪枝函式,只留下相鄰頂點顏色不重複的分支,繼續遞迴求解
void BackTrack(int t) {
if (t > n)
sum++;
else
for (int i = 1; i <= m; i++) {
x[t] = i;
if (ok(t))
BackTrack(t + 1);
}
}
void main() {
m = 3;
BackTrack(1);
printf("%d\n", sum);
system("pause");
}