目录
一、问题描述
地图着色问题:如果把每一个区域收缩为一个顶点,把相邻两个区域用一条边相连接,就可以把一个区域图抽象为一个平面图。用m种颜色为图中的每个顶点着色,要求每个顶点着一种颜色,并使相邻两顶点之间有着不同的颜色。运用回溯法解决该问题。
二、解题思路
考虑所有的图,讨论在至多使用m种颜色的情况下,可对一给定的图着色的所有不同方法。通过回溯的方法,不断的为每一个节点着色,在前面n-1个节点都合法的着色之后,开始对第n个节点进行着色,这时候枚举可用的m个颜色,通过和第n个节点相邻的节点的颜色,来判断这个颜色是否合法,如果找到那么一种颜色使得第n个节点能够着色,那么说明m种颜色的方案是可行的。
用图的邻接矩阵c表示无向连通图G = (V , E)。若(I,j)属于图的边集,则c[i][j] = 1,否则c[i][j] = 0。整数1~m表示m种不同的颜色。顶点i所着的颜色用x[i]表示。数组x[1:n]是问题的解向量。问题的解空间就是这些解向量的集合。
不难看出,该问题的解空间可以表示为一颗高度为n+1的完全m叉树,并且是排列树。解空间树的第i(1<=i<=n)层中的每个节点都有m个儿子,每个儿子对应x[i]的m个可能着色之一。第n+1层均为叶子结点。
三、代码
#include<iostream>
#include<stdio.h>
using namespace std;
int c[100][100]; //邻接矩阵
int color[100]; //记录每个顶点的颜色
int count,m,n; //count记录方案数 n个顶点 m种颜色
int Check(int k) //检查第i个顶点的颜色是否满足条件
{
for(int i=1;i<=k;i++)
{
if(c[k][i]==1&&color[i]==color[k]) //k与i之间相连并且i顶点的颜色与k顶点的颜色相同
return 0;
}
return 1;
}
void GraphColor(int step)
{
if(step==n+1) //表示前面所有的顶点颜色都已经填完
{
for(int i=1;i<=n;i++)
printf("%d ",color[i]);
count++;
printf("\n");
return ;
}
else
{
for(int i=1;i<=m;i++)
{
color[step]=i; //首先将这个顶点颜色换为i
if(Check(step)==1) //检查是否符合条件
{
GraphColor(step+1); //符合条件则走下一步
}
color[step]=0; //回溯 置为0
}
}
}
int main(void)
{
printf("请输入顶点数:");
scanf("%d",&n);
printf("\n");
printf("请输入颜色数:");
scanf("%d",&m);
printf("\n");
printf("请输入邻接矩阵:\n");
for(int i=1;i<=n;i++)
for(int j=1;j<=n;j++)
{
cin>>c[i][j];
}
printf("\n方案如下:\n");
GraphColor(1);
printf("\n");
printf("%d",count);
return 0;
}
四、结果
说明:此次测试顶点数为5,颜色为4,邻接矩阵如上图所示,经计算有48种方案,结果正确。
五、总结
1. 回溯法是一种选优搜索法,又称为试探法。用它可以系统的搜索一个问题的所有解或任一解。是一个既带有系统性又带有跳跃性的搜索算法。在包含问题的所有解的解空间树中,按照深度优先搜索的策略,从根结点出发深度探索解空间树。当探索到某一结点时,要先判断该结点是否包含问题的解,如果包含,就从该结点出发继续探索下去,如果该结点不包含问题的解,则逐层向其祖先结点回溯。(其实回溯法就是对隐式图的深度优先搜索算法)。若用回溯法求问题的所有解时,要回溯到根,且根结点的所有可行的子树都要已被搜索遍才结束。而若使用回溯法求任一个解时,只要搜索到问题的一个解就可以结束。
2. 在用回溯法搜索解空间树时,通常采用两种策略来避免无效搜索,提高回溯法的搜索效率。其一是用约束函数在扩展结点处剪去不满足约束的子树;其二是用限界函数剪去不能得到最优解得子树。这两类函数统称剪枝函数。
运用回溯法解题通常包含以下三个步骤:
(1)针对所给问题,定义问题的解空间
(2)确定易于搜索的空间结构
(3)以深度优先的方式搜索解空间,并且在搜索过程中用剪枝函数避免无效搜索。
3.本次实验内容是在填写每一个顶点的颜色时检查与相邻已填顶点的颜色是否相同。如果不同,则填上;如果相同(冲突),则另选一种;如果已没有颜色可供选择,则回溯到上一顶点。重复这一过程,直到所有顶点的颜色都已填上。是一道典型的回溯题目。