目录
问题描述
四色定理(世界近代三大数学难题之一),又称四色猜想、四色问题,是世界三大数学猜想之一。四色定理的本质正是二维平面的固有属性,即平面内不可出现交叉而没有公共点的两条直线。用数学语言表示即“将平面任意地细分为不相重叠的区域,每一个区域总可以用1234这四个数字之一来标记而不会使相邻的两个区域得到相同的数字。”这里所指的相邻区域是指有一整段边界是公共的。如果两个区域只相遇于一点或有限多点就不叫相邻的。因为用相同的颜色给它们着色不会引起混淆。很多人证明了二维平面内无法构造五个或五个以上两两相连区域,但却没有将其上升到逻辑关系和二维固有属性的层面,以致出现了很多伪反例。
解决思路
首先考虑的是如何将地图存储,我们只 关心图与图之间的相邻关系,所以我们 选择图的邻接矩阵来存储图,如果i区域 和j区域相邻,那么我们就对[i][j]和[j][i] 赋值为1,不相邻的区域赋值为0。
则该图用领接矩阵表示为
{ 0, 1, 1, 1, 1, 1,
1, 0, 1, 0, 1, 0,
1, 1, 0, 1, 1, 1,
1, 0, 1, 0, 0, 1,
1, 1, 1, 0, 0, 1,
1, 0, 1, 1, 1,0 }
染色思路
每一个区域的染色用0,1,2,3逐个尝 试,如果染色与相邻区域的颜色不同, 就将此颜色入栈。如果染色与相邻区域的 颜色相同,则尝试下一个颜色。如果尝试 到最后仍然重色,则退栈至上一个区域, 看此区域是否可染其他颜色,若能,则换 色后继续对下一区域染色,若不能,则再 退栈至上一区域,看是否能染其他颜色… 如此循环,直至所有区域染色成功。
代码示例
#include<stdio.h>
int detection(int map[6][6], int stack[], int top) //检查是否撞色
{
int j;
for (j = 0; j < top; j++)
{
if (map[j][top] == 1 && stack[top] == stack[j])//如果相邻且颜色相同则返回1,不同返回0
{
return 1;
}
}
return 0;
}
int main()
{
char *colorarr[4] = { "红色","绿色","蓝色","黄色" };//颜色数组
int num;
printf("请输入共几块地:");
scanf("%d",&num);
int arr[num][num];
int i,j,k;
for(i=0;i<num;i++)
{
printf("请输入第%d块地与其余是否相邻(1表示是,0表示否):",(i+1));
for(j=0;j<num;j++)
{
scanf("%d",&arr[i][j]);
}
}
int stack[num];//定义栈
int top = 0;
int color = 0;//颜色0
stack[top] = color;//第一块区域染色,颜色0入栈
top++;
while (top < num)
{
while (color < 4&&top < num)
{
stack[top] = color;//由0开始染色
while (detection(arr, stack, top))//检验是撞色
{
color++;//如果撞色则尝试下一个颜色
stack[top] = color;
}
if (color < 4)//看看颜色是否符合要求
{
top++;//符合要求就将颜色入栈
color = 0;//颜色要重置为0
}
}
if (color >= 4)//颜色不符合条件就要开始回溯
{
top--;
color = stack[top] + 1; //在原有颜色基础上尝试下一种颜色
}
}
for (k = 0; k < num; k++)
{
printf("第%d块地的颜色是%s\n", k+1, colorarr[stack[k]]);
}
return 0;
}
运行示例