一.問題分析
地圖着色問題是01揹包問題的推廣,可以抽象看作無向連通圖
由0/1兩種狀態變成了{1,2,3....N} 這N種狀態,邏輯結構也從二叉樹->N叉樹.
這時就不能像之前那樣:左子樹寫一段代碼,右子樹寫一段代碼.
用for()遍歷每一個狀態並遞歸,而且因爲沒有"不塗色",也就是說沒有0狀態,所以也不存在限界條件
二.代碼分析
分爲4部分
1.全局變量定義
2.約束函數
3.初始化函數
4.遞歸函數
1.定義全局變量
const int M3 = 21;
int map[M3][M3]; //記錄結點的連接狀況,1表示連接,0表示未連接
int n3; //表示n個結點
int e; //表示有e條邊
int color_num; //用戶輸入顏色數量,小於M3
int color[M3]; //color[1]=2表示結點1的顏色是2
int countg = 0; //記錄最優解
2.約束函數
約束函數的功能:
如果 目前元素 t 與元素 0 ~ t-1 中,有相鄰並且顏色一樣的,返回false
bool place3(int t) //t表示當前結點的序號
{
bool flag = true;
for (int i = 1; i < t; i++) //檢查當前結點和之前的全部結點 是否相鄰並且同色
{
if (map[t][i] && color[t] == color[i])
{
flag = false;
break;
}
}
return flag;
}
3.初始化函數
用戶自定義元素個數(int)、聯通情況(int[ ][ ])、顏色數量(int)
void creategraph()
{
cout << "請輸入1~20以內的數作爲圖的結點個數:";
cin >> n3;
if (n3 > 20)
{
cout << "輸入值偏大,請重新輸入:";
cin >> n3;
}
cout << "請輸入顏色的個數:";
cin >> color_num;
if (n3 < 2)
{
cout << "不可能有此輸入值,請重新輸入:";
cin >> color_num;
}
int u, v;
cout << "輸入邊數 "; cin >> e; cout << endl;
cout << "輸入結點1~結點20中,有邊連接的點u和v\n";
for (int i = 0; i < e; i++)
{
cout << "輸入第"<<i+1<<"條邊的端點1: ";
cin >> u; cout << endl;
cout << "輸入第" << i + 1 << "條邊的端點2: ";
cin >> v; cout << endl;
map[u][v] = 1;
map[v][u] = 1;
}
}
4.遞歸函數
void GraphColor(int t)//i表示圖裏有i個結點
{
//先寫終止條件
if (t>n3) //此時已遞歸完所有結點 (這裏的元素是從1開始的,所以不是">=")
{
countg++; //解的數量多了一種
for (int i = 1; i <= n3; i++)
{
cout << color[i] << "\t";
}
cout << endl;
}
else
{
for (int i = 1; i <= color_num; i++)
{
color[t] = i;
if (place3(t))
{
GraphColor(t + 1);
}
}
}
}