图着色问题(Graph Coloring Problem, GCP) 又称着色问题,是最著名的NP-完全问题之一。道路着色问题(Road Coloring Problem)是图论中最著名的猜想之一。给定一个无向图G=(V, E),其中V为顶点集合,E为边集合,图着色问题即为将V分为K个颜色组,每个组形成一个独立集,即其中没有相邻的顶点。其优化版本是希望获得最小的K值。
解此问题我用的是回溯法.
所谓回溯法,本质其实就是一种蛮力法,只是通过一定的方法可以使得蛮力法中的一些基本情况可以提前排除从而提高蛮力算法效率,回溯可以理解为排除这些不满足条件的基本情况的过程。
①初始化颜色总数为无穷多种。
②每次从点集中选择一个顶点并从第一种颜色开始尝试对其进行着色;
③如果着色不冲突,则继续通过相同的方式处理点集中的下一个顶点;如果着色冲突,则说明该种着色方法行不通,退回到上一个结点,将上一个结点的着色改为当前着色的下一种颜色。
④重复上述过程,直到所有的顶点都着色为止,此时确定了一个可行解。如果可行解的颜色数少于当前颜色总数,则将颜色总数更新为可行解的颜色数。
⑤得到一个可行解后进行回溯,退回到上一个着色颜色序号小于当前颜色总数的结点上,将其着色改为下一种,并进行如上所示的推理过程。
⑥当存在一个结点没有颜色可以着色时,算法停止。当前最优解即全局最优解。
代码附下.
#include <iostream>
#include <vector>
using namespace std;
const int N = 15;
int n, m, a, b;
int color[N], puted[N];
vector <int> G[N];
bool check(int c)
{
for (int i = 0; i < G[c].size(); i ++ )
if(color[c] == color[G[c][i]]) return false;
return true;
}
bool dfs(int cur, int k)
{
if(cur > n)
{
printf("染色成功\n\n");
printf("最少需要%d种颜色\n\n", k);
printf("接下来分别是每个点染上的颜色\n\n");
for(int i = 1; i <= n; i ++ )
{
printf("第%d个点的颜色是%d ", i, color[i]);
if (i % 5 == 0) printf("\n");
}
printf("\n\n方案输出完毕");
printf("\n");
return true ;
}
if (!puted[k]) printf("正在尝试能否用%d种颜色为图染色\n", k), puted[k] = true;
printf("目前正在给点%d染色\n", cur);
for(int clr = 1; clr <= k; clr ++ )
{
color[cur] = clr;
if(check(cur)) { printf("点%d成功染上第%d钟颜色\n\n", cur, clr); return dfs(cur + 1, k); }
else printf("对于%d点染第%d种颜色出现冲突\n\n", cur, clr);
color[cur] = 0;
}
}
int main()
{
printf("输入点数n, 边数m\n");
cin >> n >> m;
printf("输入%d条无向边, 每行两个整数a,b,表示a和b之间有一条无向边\n\n",m);
while (m -- )
{
scanf("%d%d", &a, &b);
G[a].push_back(b), G[b].push_back(a);
}
for (int i = 1; i <= n; i ++ )
if (!dfs(1, i)) printf("不可以用第%d种颜色为图染色\n\n", i);
else return 0;
return 0;
}
总结
经过这次课程设计实验,我体会到只有保持耐心,坚持到底才有可能做好事情。这次课程设计加强了我动手解决问题的能力,巩固和加深了对数据结构的理解,提高了综合运用课程知识的能力,培养了独立思考、深入研究、分析问题和解决问题的能力。
同时,我也明白了将理论知识与实际相结合的重要性,只有理论知识远远不够,因为在实际设计中还是会遇到不少问题,这次实验使我发现了自己很多知识漏洞,这对我今后的学习来说是一次非常宝贵的体验。