图的着色问题--C++实现(含详细注释)

合集下载
  1. 1、下载文档前请自行甄别文档内容的完整性,平台不提供额外的编辑、内容补充、找答案等附加服务。
  2. 2、"仅部分预览"的文档,不可在线预览部分如存在完整性等问题,可反馈申请退款(可完整预览的文档不适用该条件!)。
  3. 3、如文档侵犯您的权益,请联系客服反馈,我们会尽快为您处理(人工客服工作时间:9:00-18:30)。

图的着色问题
一、题目简述
(1) 图的m-着色判定问题
给定一个无向连通图 G 和 m 种不同的颜色。

用这些颜色为图 G 的各顶点着色,每个顶点着一种颜色,是否有一种着色法使 G 中任意相邻的两个顶点着不同颜色?
(2) 图的m-着色优化问题
若一个图最少需要 m 种颜色才能使图中任意相邻的两个顶点着不同颜色,则称这个数 m 为该图的色数。

求一个图的最小色数 m 的问题称为m-着色优化问题。

二、算法思想
1. m-着色判定问题
总体思想:通过回溯的方法,不断为每一个节点着色,每个点的颜色由一个数字代表,初始值为1。

在对前面 step - 1 个节点都合法的着色之后,开始对第 step 个节点进行着色。

如果 n 个点均合法,且颜色数没有达到 m 种,则代表存在一种着色法使 G中任意相邻的两个顶点着不同颜色。

具体步骤:
1. 对每个点 step ,有 m 种着色可能性,初始颜色值为1。

2. 检查第 step 个节点颜色的可行性,若与某个已着色的点相连且颜色相同,则不选择这种着色方案,并让颜色
值加1,继续检查该点下一种颜色的可行性。

3. 如果第 step 点颜色值小于等于 m ,且未到达最后一个点,则进行对第 step + 1 点的判断。

4. 如果第 step 点颜色值大于 m ,代表该点找不到合适的分配方法。

此时算法进行回溯,首先令第 step 节点的
颜色值为0,并对第 step - 1 个点的颜色值+1后重新判断。

5. 如果找到一种颜色使得第 step 个节点能够着色,说明 m 种颜色的方案是可行的。

6. 重复步骤2至5,如果最终 step 为0则代表无解。

2. m-着色优化问题
基于问题1,对于一个无向图 G ,从1开始枚举染色数,上限为顶点数,第一个满足条件的颜色数即为所求解。

三、实现过程(附代码)
1. m-着色判定问题
#include<iostream>
using namespace std;
int color[100]; // 每个点的颜色
int mp[100][100]; // 图的邻接矩阵
int n, m, x; // n顶点,m种颜色方案,x条边
bool check(int step) {
// 判断与step点相邻的点,颜色是否与step点相同,若相同则返回false
for (int i=1; i<=n; i++) {
if (mp[step][i] ==1&&color[i] ==color[step]) {
return false;
}
}
return true;
}
bool Solve(int m) {
// 求解是否可以找到一种可行的染色方案
int step=1; // step指示当前节点
while (step>=1) {
color[step] +=1; // 假定颜色值从1开始,若为回溯,选择下一种方案
while (color[step] <=m) { // 按照问题条件选择第step点颜色
if (check(step)) {
break;
} else {
color[step]++; // 搜索下一个颜色
}
}
if (color[step] <=m&&step==n) { // 如果找完n个点,且染色方法小于等于m种 return true;
} else if (color[step] <=m&&step<n) {
step++; // 求解下一个顶点
} else { // 如果染色数大于m个,回溯
color[step] =0; // 回溯,该点找不到合适的分配方法,对上一点进行分析
step--;
}
}
// 如果step退到0,则代表无解
return false;
}
int main() {
int i, j;
bool ans=false;
cout<<"输入顶点数n和着色数m"<<endl;
cin>>n>>m;
cout<<"输入边数"<<endl;
cin>>x;
cout<<"具体输入每条边"<<endl;
for (int p=0; p<x; p++) { // 以无向邻接矩阵存储边
cin>>i>>j;
mp[i][j] =1;
mp[j][i] =1;
}
if (Solve(m)) {
cout<<"有解";
} else {
cout<<"无解";
}
return0;
}
2. m-着色优化问题
#include<iostream>
using namespace std;
int color[100]; // 每个点的颜色
int mp[100][100]; // 图的邻接矩阵
int n, m, x; // n顶点,m种颜色方案,x条边
bool check(int step) {
// 判断与step点相邻的点,颜色是否与step点相同,若相同则返回false
for (int i=1; i<=n; i++) {
if (mp[step][i] ==1&&color[i] ==color[step]) {
return false;
}
}
return true;
}
bool Solve(int m) {
// 求解是否可以找到一种可行的染色方案
int step=1; // step指示当前节点
while (step>=1) {
color[step] +=1; // 假定颜色值从1开始,若为回溯,选择下一种方案
while (color[step] <=m) { // 按照问题条件选择第step点颜色
if (check(step)) {
break;
} else {
color[step]++; // 搜索下一个颜色
}
}
if (color[step] <=m&&step==n) { // 如果找完n个点,且染色方法小于等于m种 return true;
} else if (color[step] <=m&&step<n) {
step++; // 求解下一个顶点
} else { // 如果染色数大于m个,回溯
color[step] =0; // 回溯,该点找不到合适的分配方法,对上一点进行分析
step--;
}
}
// 如果step退到0,则代表无解
return false;
}
int main() {
int i, j;
bool ans=false;
cout<<"输入顶点数n"<<endl;
cin>>n;
cout<<"输入边数"<<endl;
cin>>x;
cout<<"具体输入每条边"<<endl;
for (int p=0; p<x; p++) { // 以无向图邻接矩阵存储边 cin>>i>>j;
mp[i][j] =1;
mp[j][i] =1;
}
for (m=1; m<=n; m++) { // 从小到大枚举着色数m
if (Solve(m)) { // 如果有解,输出答案并跳出循环
cout<<"最小色数m为 "<<m;
break;
}
}
return0;
}
四、结果及分析
问题1测试用例:
问题2测试用例:
经检验,最少着色数的范围为2-4,意味着使 G 中任意相邻的两个顶点着不同颜色最多需要4种颜色。

该算法程序能较好地解决图着色问题,但是如果算法输入规模较大,程序复杂度将大大增加,运行效率将会降低。

该程序还需要很多优化的地方。

五、体会
回溯算法类似于深度优先搜索,如果某次搜索能满足条件,则向更深层继续搜索,直至得到解;否则在不满足条件时,向上回溯,重新选择,再向更深层判断。

这样的算法思想有助于在解决其他问题时使用:当某次决策无法得到可行解时,先更改前面的决策,再继续往后寻找可行解。

相关文档
最新文档