给定无向连通图G和m种不同的颜色。用这些颜色为图G的各顶点着色,每个顶点着一种颜色。如果有一种着色法使G中每条边的两个顶点着不同颜色,则称这个图是m可着色的。图的m着色问题是对于给定图G和m种颜色,找出所有不同的着色法。
函数接口定义:
void dfs(int i);
裁判测试程序样例:
#include <stdio.h>
#include <string.h>
#define MAXN 20 //图最多的顶点个数
int n,k,m;
int a[MAXN][MAXN];
int count=0; //全局变量,累计解个数
int x[MAXN]; //全局变量,x[i]表示顶点i的着色
bool Same(int i) //判断顶点i是否与相邻顶点存在相同的着色
{
for (int j=1;j<=n;j++)
if (a[i][j]==1 && x[i]==x[j])
return false;
return true;
}
int main()
{
memset(a,0,sizeof(a)); //a初始化
memset(x,0,sizeof(x)); //x初始化
int x,y;
scanf("%d%d%d",&n,&k,&m); //输入n,k,m
for (int j=1;j<=k;j++)
{
scanf("%d%d",&x,&y); //输入一条边的两个顶点
a[x][y]=1; //无向图的边对称
a[y][x]=1;
}
dfs(1); //从顶点1开始搜索
if (count>0) //输出结果
printf("%d",count);
else
printf("-1");
return 0;
}
/* 请在这里填写答案 */
输出格式:
程序运行结束时,将计算出的不同的着色方案数输出。如果不能着色,程序输出-1。
输入样例:复制
5 8 4
1 2
1 3
1 4
2 3
2 4
2 5
3 4
4 5
输出样例:复制
48
首先看题目,了解题意,简单来说就是给了我们n个点,每个点可有m种颜色 ,然后就是这几个点并不是任意两两相连,题目给出了相连两点的编号,然后我们的目的就是查找有多少种可能可以是任意两两相连的点颜色都不一致,因为给出的n的范围并不算大,我们可以考虑使用暴力算法来解决此题,具体来说就是给每个点每个颜色都考虑进来,然后调用Same函数来判断是否符合规则(Same函数已经给出,题目难度已经下降了一个档次,可是我还是写了好久,还问了其他人才写出来,有点菜了),其实回溯算法思想很简单,我们可以用树来帮助我们理解,该树一共有五层,每一层代表一个点,当涂到第五层的时候就说明已经每个点都有了颜色,此时我们便可以调用Same函数对每个点来进行判断了,回溯算法简单来说就是对每一层刚开始都是颜色1(m种颜色用1到m来表示,即刚开始五个点都是1颜色,然后对于最后一层先改变成2然后一直到m,这个时候倒数第二层为一的所有情况已经列举完毕了,然后回溯到倒数第二层,让第二层的颜色由一变成二,以此类推,一直回溯罗列所有情况,这个是回溯算法的基本思路,然后就是代码的具体实现了。我先将我之前写的错误代码贴上来。
t代表第几层,然后一直先给第一层从一开始赋值,一直到最后,可是我这个代码犯了很严重的错误就是算多了情况,比如对与样例n=2,k=1,m=2;即一条边,两个点两个颜色,首先是第一次先给第一层与第二层赋值为1,然后在i等于二的那一层对于第二个点赋值为一和二,这些都没毛病,然后就是回到第一层此时问题来了,i回到了1那一层,此时我们应该是想要让他到第二个数字也就是第二种颜色,其实这也能做得到,但是在将2赋值给第一层后,那个i还是一,也就是说在经历了这一次j从一到m后,i才到二继续填颜色,这就是多出来的部分了,会导致count的数量增多。
而改正过来也很简单,就是把外层的for循环丢掉,然后i换成t来记录第几层。到这里题目已经基本完成了,反思就是如何正确的去用代码来讲我们的思路给好好的复现出来呢,我认为可以和我那样现象一个简单的例子来模拟程序运行的过程,最后就是得多练吧,希望对你有帮助,一起加油吧!