问题引入:
给定无向连通图G=(V,E)和正整数m,寻找最小的整数m,用m种颜色对G中的顶点着色,使得任意两个相邻顶点着色不同。
由于用m种颜色为无向图G=(V,E)着色,其中,V 的顶点个数为n,可以用一个n元组C=(c1,c2,⋯,cn) 来描述图的一种可能着色,其中,ci∈{1,2,⋯,m}(1⩽i⩽n) 表示赋予顶点i的颜色。例如,5元组(1,2,2,3,1)表示对具有5 个顶点的无向图的一种着色,顶点1着颜色1,顶点2着颜色2,顶点3 着颜色2,如此等等。par 如果在n元组C中,所有相邻顶点都不会着相同颜色,就称此n 元组为可行解,否则为无效解。
回溯法求解图着色问题,首先把所有顶点的颜色初始化为0,然后依次为每个顶点着色。在图着色问题的解空间树中,如果从根结点到当前结点对应一个部分解,也就是所有颜色指派都没有冲突,则在当前结点处选择第一棵子树继续搜索,也就是为下一个顶点着颜色1,否则,对当前子树的兄弟子树继续搜索,也就是为当前顶点着下一个颜色,如果所有m种颜色都已尝试过并且都发生冲突,则回溯到当前结点的父结点处,上一个顶点的颜色被改变,依此类推。下图是回溯法求解一个5阶图的解空间树。
![bb049e345c1c8691ee9551e6fec63cf4.png](https://img-blog.csdnimg.cn/img_convert/bb049e345c1c8691ee9551e6fec63cf4.png)
要求:运用回溯法策略编写一个能找出最少着色数,并能对图进行着色的函数。编写的程序必须对如下图中给出的各图能进行着色。
![e07ac398a44b521088cd620d0e9f5e59.png](https://img-blog.csdnimg.cn/img_convert/e07ac398a44b521088cd620d0e9f5e59.png)
输入样例:
如下给出的输入样例中,第一行的两个数据分别是图的顶点数和边数,从第二行开始,每行3个数据,分别是两个关联顶点及其权值。输数据的总行数为输入的边数加1.
5 7
0 1 1
0 2 1
1 2 1
1 3 1
1 4 1
2 4 1
3 4 1
输出样例:
在输出样例中,[]前的数据为最小着色数,[]中的数分别是各顶点着色的颜色编号
3[1,2,3,3,1]
代码:
#include <stdio.h>
#include <stdlib.h>
#define INFINITY 255 //表示图中两个顶点无关联
typedef struct{
int vertexNum; //图的顶点数
int arcNum; //图的边数
int *arc; //指向图中顶点的关联关系数组
int *color; //指向各顶点着色情况数组
}Graph;
void creatGraph(Graph *g);
int ColorGraph(Graph *g);
int Conflict(Graph *g,int k);
void dispVertexColor(Graph *g);
int main()
{
Graph g; //声明一个Graph类型的图g
creatGraph(&g);//给图g定义顶点数、边数、生成顶点之间的关联关系
int m=ColorGraph(&g);
printf("%d",m);
dispVertexColor(&g);
return 0;
}
/**
* 以下creatGraph()函数
* 定义图的定点数、边数、
* 图的邻接矩阵、顶点着色记录数组
**/
void creatGraph(Graph *g)
{
int x,y,k,w;
scanf("%d %d",&g->vertexNum,&g->arcNum);
g->arc=(int*)malloc(sizeof(int)*g->vertexNum*g->vertexNum);//创建邻接矩阵
g->color=(int*)malloc(sizeof(int)*g->vertexNum);//创建顶点着色记录数组
if(g->vertexNum==1&&g->arcNum==0)
{
g->arc[0]=0;
g->color[0]=1;
return;
}
for(x = 0;x < g->vertexNum;x++){//初始化邻接矩阵中的元素为INFINITY,即顶点之间不连通
for(y = 0;y < g->vertexNum;y++)
g->arc[g->vertexNum * x + y]=INFINITY;
g->color[x]=0;//初始化着色记录数组元素为0,即无色。
}
for (k = 0; k < g->arcNum; k++){ //关联矩阵为一个对称矩阵
scanf("%d %d %d",&x,&y,&w);
g->arc[g->vertexNum*x+y]=w; //将关联边长度存入图的矩阵x行y列
g->arc[g->vertexNum*y+x]=w; //将关联边长度存入图的矩阵y行x列
}
}
void dispVertexColor(Graph *g) //输出图g中各顶点的着色情况函数
{
printf("[");
for(int i = 0;i < g->vertexNum - 1; i++)
printf("%d,",g->color[i]);
printf("%d]n",g->color[g->vertexNum - 1]);
}
int ColorGraph(Graph *g) //给图的顶点着色,函数返回值为最小着色数的值。
{
int k=0,m=1;
if(g->vertexNum==1 && g->arcNum==0)
{
g->color[0]=1;
return m;
}
while(1)
{
while(k>=0)
{
g->color[k]=g->color[k]+1;
while(g->color[k]<=m)
{
if(Conflict(g,k)) break;
else g->color[k]=g->color[k]+1;
}
if(g->color[k]<=m && k==g->vertexNum-1)
return m;
if(g->color[k]<=m && k<g->vertexNum-1)
k=k+1;
else
g->color[k--]=0;
}
k=0;
m++;
}
}
int Conflict(Graph *g,int k) //检测顶点k与其邻接点着色是否冲突检,返回1为不冲突,返回0为冲突,此函数由ColorGraph()函数调用
{
for(int i=0;i<k;i++)
{
if(g->arc[g->vertexNum*k+i]!=255&&g->color[i]==g->color[k])
return 0;
}
return 1;
}