地圖四色着圖的C語言實現

四色問題又稱四色猜想、四色定理,是世界三大數學猜想之一。四色定理是一個著名的數學定理,通俗的說法是:每個平面地圖都可以只用四種顏色來染色,而且沒有兩個鄰接的區域顏色相同。1976年藉助電子計算機證明了四色問題,問題也終於成爲定理,這是第一個藉助計算機證明的定理。(這段文字來源於百度百科)

這篇文章主要介紹利用C語言實現地圖四色着圖。主要包括:設計的數據結構;算法實現等。


1 着圖的數據結構

着圖時無需表示具體的地圖多邊形,只需要表示多邊形的Voronoi圖即可,說的簡單點可見下圖:

對於左邊的地圖多邊形,在算法中只需要表示成圖形右邊的即可。其中結點(v1, v2…)表示的是地圖多邊形,結點的連線表示兩個多邊形之間是比鄰的關係。

因此在數據結構中只需要表示成圖的形式即可。這裏採用“鄰接表”的數據結構,如下:

#include <stdio.h>
#include <malloc.h>
#include <stdlib.h>
#define MAX_VERTEX_NUM 20
typedef struct ArcNode {
	int adjvex; //該邊指向的頂點的位置
	struct ArcNode *nextarc; //指向下一條邊的指針
} ArcNode, *ArcNList; 
typedef struct {
	float x;
	float y;
} Vertex; //點
typedef struct VNode {
	Vertex data; //頂點信息
	ArcNList firstarc; //指向第一條依附該頂點的邊的指針
	int color; //該點的顏色
} VNode, AdjList[MAX_VERTEX_NUM];
typedef struct{ 
	AdjList vertics; 
	int vexnum, arcnum; //該圖的當前頂點數和邊數
} UDGraph;

2 着圖的算法

着色的算法採用回溯法。基本思路爲:首先對一個多邊形進行着色,着色後判斷是否滿足要求,如果滿足要求則繼續對其他多邊形進行着色;如果不滿足要求則撤銷當前着色並回溯,採用其他着色方案。遞歸如此,直到地圖全部着色完成。

地圖四色染圖的C語言代碼實現如下。其首先給定地圖最多使用的顏色數量爲4,判斷能否只利用4種顏色對地圖進行着色,如果能則返回true,反之則返回false。

bool isColorOK(UDGraph G, int node) { //判斷對第node個結點着色的方案行不行
	VNode V = G.vertics[node - 1];
	ArcNList T = V.firstarc;
	while(T) {
		if(V.color == G.vertics[T->adjvex].color) return false;
		T = T->nextarc;
	}
	return true;
}
bool getColorPowset(UDGraph &G, int color_Num, int step, int a, int b) { //**回溯法對圖着色
	if(step > G.vexnum) {
		if(G.vertics[a-1].color == b) { //在a區域圖上了b色
			return true;
		}
	} else {
		int i;
		for(i=1; i<=color_Num; i++) {
			G.vertics[step - 1].color = i;
			if(isColorOK(G, step)) {
				if(getColorPowset(G, color_Num, step + 1, a, b)) return true;
			}
			G.vertics[step - 1].color = 0;
		}
	}
	return false;
}

3 測試運行

測試過程的代碼包括:建圖的過程、輸出着色結果的過程。這兩個過程的代碼如下:

int createUDGraph(UDGraph &G) {
	int a, b, i;
	ArcNList p;
	printf("請輸入結點的個數和邊的個數:");
	scanf("%d,%d", &(G.vexnum), &(G.arcnum));
	getchar(); //消除回車
	for(i=0; i<G.vexnum; i++) {//初始化各結點
		G.vertics[i].firstarc =NULL;
		G.vertics[i].color = 0;
	}
	printf("請輸入這%d個點之間的拓撲關係:\n", G.vexnum);
	//接下來就是創建這G.arcnum*2個邊
	for(i=1; i<=G.arcnum; i++) {
		scanf("%d,%d", &a, &b); //表明a點和b點之間向鄰接,在a點和b點之間連上線
		getchar();//消除回車
		p = (ArcNList)malloc(sizeof(ArcNode)); if(!p) exit(-2);
		p->adjvex = b - 1;
		p->nextarc = G.vertics[a - 1].firstarc;
		G.vertics[a - 1].firstarc = p;
		//以上是在a點上加上一個結點,一下是在b點上加上一個結點
		p = (ArcNList)malloc(sizeof(ArcNode)); if(!p) exit(-2);
		p->adjvex = a - 1;
		p->nextarc = G.vertics[b - 1].firstarc;
		G.vertics[b - 1].firstarc = p;
	}
	return 1;
}
void outputGraph(UDGraph G) {
	int i;
	for(i=0; i<G.vexnum; i++) printf("結點%d的着色方案爲:%d\n", i+1, G.vertics[i].color);
}
int main() {
	int a, b;//a區域圖b色
	UDGraph G;
	createUDGraph(G);
	printf("請輸入一種着色方案(即哪一個區域着什麼顏色):");
	scanf("%d,%d", &a, &b);//在a區域圖上b色
	getchar();//消除回車
	if(getColorPowset(G, 4, 1, a, b)) {//如果最後的圖色成功
		printf("圖形圖色成功,爲:\n");
		outputGraph(G);
	} else printf("圖形圖色失敗,方案不正確\n");//如果最後的圖色成功
	return 1;
}

運行上述代碼,測試如下:

其圖形含義如下:



如果想自己編譯運行,只需要將本文所有的代碼拷貝到一起即可編譯運行。

全文完。轉載請註明出處。


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