算法分析 | 回溯法 | 地圖着色

一.問題分析

地圖着色問題是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);
			}
		}
	}
	
}

 

 

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