四色問題又稱四色猜想、四色定理,是世界三大數學猜想之一。四色定理是一個著名的數學定理,通俗的說法是:每個平面地圖都可以只用四種顏色來染色,而且沒有兩個鄰接的區域顏色相同。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;
}
運行上述代碼,測試如下:
其圖形含義如下:
如果想自己編譯運行,只需要將本文所有的代碼拷貝到一起即可編譯運行。
全文完。轉載請註明出處。