45fan.com - 路饭网

搜索: 您的位置主页 > 电脑频道 > 编程代码 > 阅读资讯:给地图填色的方法技巧

给地图填色的方法技巧

2016-08-26 07:06:27 来源:www.45fan.com 【

给地图填色的方法技巧

【问题描述】
1976年,美国科学家Appel和Haken利用计算机证明了:对一张地图,可以用不超过4种颜色对其填色,使得相邻的区域填上不同的颜色。现在我们就来模拟这一填色过程,输入一张行政区地图(见图10-2),用4种颜色对其填色,要求相邻的行政区域内没有相同的颜色,给出所有的填色方案,并统计方案的个数。
【数据描述】
首先考虑如何存储行政区地图,由于邻接矩阵能更好地描述各行政区之间的关系,我们采用邻接矩阵G来存储地图。邻接矩阵G可以用二维数组表示;另设一维数组color[i]记录第 i(i=0...n-1)个行政区所填的颜色,分别取值为:{1(红),2(黄),3(蓝),4(绿)};数据描述如下:

int G[n][n];

int color[n+1];

【算法描述】
该问题的实现是从第一个行政区到最后一个行政区依次填色的过程,如果采用递归的算法,可以简单描述如下:

Void trycolor(&color[],i){

// 设前i-1个行政区已经填好颜色,现对第i个行政区用递归法填色;

for (c=1;c<=4;c++)

{对第i个行政区填上c颜色;检查其合法性;

if (合法)

if (i<n) tricolor(&color[],i+1); //递归

else 打印一种填色方案; //递归出口

} //end_for

} //end_tricolor

如果采用非递归的算法,可用试探和回溯来实现:对每一个行政区(用邻接矩阵表示后,可称为结点)先试填一个颜色,在确定其合法性后,再填下一个结点;如果4种颜色都填完后仍不合法,就回溯到上一个结点重新填色。算法描述如下:

Color[0..n-1]=0; 选择第一个行政区为当前要处理的结点;

do

{
将当前结点顺序向后试填一个颜色;

if (所填颜色合法)

当前区域确定了所填的颜色;

if (当前结点是最后一个区域)

{打印一种填色方案;if (所填颜色是4) 回溯到上一个结点继续填色;}

else 下一个结点设为当前结点;

else if (所填颜色是4) 回溯到上一个结点;}
while(所有的结果都试探完);

现在的问题是:如何确定合法的填色?设前i-1个行政区已经填好颜色,现对第i个行政区填色c,通过邻接矩阵的定义,我们可以分析出这样的结论:

for (k=0;k<=i-1;k++)

if (color[k]*G[i][k]==c)
{i与第k个结点相邻并同色,c是不合法的};

所以我们可以用color[k]*G[i][k]!=color[i]来确定当前color[i]的颜色是合法的。

如何回溯?如果对当前结点,从颜色1到颜色4都不合法,则要退到上一个结点重新填色,如果上一个结点也填了4种颜色,就继续后退;这就是回溯的思想。

【C源程序】

#define n 10

int G[n][n]={{1,1,0,1,0,1,0,0,0,0},

{1,1,1,1,0,0,0,0,0,0},

{0,1,1,1,1,0,0,0,0,0},

{1,1,1,1,1,1,1,0,0,0},

{0,0,1,1,1,0,1,0,0,0},

{1,0,0,1,0,1,1,1,0,0},

{0,0,0,1,1,1,1,1,0,1},

{0,0,0,0,0,1,1,1,1,1},

{0,0,0,0,0,0,0,1,1,1},

{0,0,0,0,0,0,1,1,1,1}};

void backtrack(int color[],int *i) /*回溯过程*/

{if (*i>0)

while (color[*i]==4) (*i)--;

}

int check(int color[], int *i) /*检查是否合法*/

{int k,b;

b=1;

for(k=0;k<=*i-1;k++)

if (color[k]*G[*i][k]==color[*i]) b=0;

if (b) return 1;

else return 0;

}

void print (int color[]) /*打印一种填色方案*/

{int k;

for (k=0;k<n;k++)

printf("%d",color[k]);

printf("/n");

}

main(){

int i,total=0;

int color[n];

for(i=0;i<n;i++) color[i]=0;

i=0;

do

{color[i]++;

if (check(color,&i))

if (i==n-1) { print(color); total++;

if (color[i]==4) backtrack(color,&i);

}

else {i=i+1;color[i]=0;}

else

if (color[i]==4) backtrack(color,&i);

}while (i);

printf("/n");

printf("total=%d",total);

scanf("/n");

}

【测试结果】以下是图10-2的部分填色方案和计算出的所有填色方案总和:

…………

1432441324

1432441342

1432443124

1432443132

1432443134

1432443142

1432443214

1432443231

1432443234

1432443241



total=528

【说明】本实验给出的方法称为回溯,这种方法可以试探性地按一定的规律例举出所有的可能性,最终找到目标结点。一般性的回溯问题可用以下算法简单描述其思想:

初始化;

do {

可行(合法)则进; //按一定顺序试探前进

不行(不合法)则换; //判断其可行性,对不可行的换成下一个试探

换不成则退; //对当前结点所有试探都不可行,回溯到上一个结点

}while(所有试探都完成);

【实验题】

1. 对行政区地图改用邻接表存储,程序应该怎样改动?

2. 将4种颜色用数字表示{1(红), 2(黄), 3(蓝), 4(绿)}改为用字符表示{‘R’(红), ’Y’(黄), ‘B’(蓝), ‘G’(绿)},改写程序完成字符的填色方案。

3. 编程递归实现地图填色问题。


本文地址:http://www.45fan.com/bcdm/67753.html
Tags: 问题 地图 填色
编辑:路饭网
推广内容
推荐阅读
热门推荐
推荐文章
关于我们 | 联系我们 | 友情链接 | 网站地图 | Sitemap | App | 返回顶部