测试例图:
程序输出结果图:
效率对比测试图:
程序输出图:
多次实验证明:回溯法比贪心法略快
源码奉上:
#include <iostream>
#include<regex>
#include <windows.h>
using namespace std;
#define MVNum 29
typedef char VerTexType;
typedef int ArcType;
typedef int Status;
static int color[100];
static string color_word[100];
static int BTcolor[100];
typedef struct
{
VerTexType vexs[MVNum]; //顶点表
ArcType arcs[MVNum][MVNum]; //邻接矩阵
int vexnum, arcnum; //图的当前点数和边数
}ALGraph;
Status LocateVex(ALGraph G, VerTexType v)
{//确定顶点在无向图G中的位置
int i;
for (i = 0; i < G.vexnum; i++)
if (G.vexs[i] == v) break;
return i;
}
Status CreateUDG(ALGraph& G)
{//采用邻接矩阵表示法,创建无向图G
cout << "****************构建无向图****************" << endl;
int i, j, k;
char v1, v2;
cout << "请输入总顶点数,总边数(以空格隔开):";
cin >> G.vexnum >> G.arcnum; //输入总顶点数,总边数
cout << "请输入点:";
for (i = 0; i < G.vexnum; ++i)
{
cin >> G.vexs[i]; //依次输入点的信息
for (j = 0; j < G.vexnum; j++)
G.arcs[i][j] = 0; ///矩阵的每个元素即边初始化为0
}
cout << "请输入边依附的顶点(例如a b)" << endl;
for (k = 0; k < G.arcnum; ++k) //构造邻接矩阵
{
cout << "请输入第" << k + 1 << "条边:";
cin >> v1 >> v2; //输入一条边依附的顶点及权值
i = LocateVex(G, v1); j = LocateVex(G, v2);//确定点v1和点v2在无向图G中的位置,即顶点数组下标
G.arcs[i][j] = 1;
G.arcs[j][i] = G.arcs[i][j]; //对称边也设为1
}
return 0;
}
int Ok(ALGraph& G, int i) //判断顶点i的着色是否发生冲突
{
for (int j = 0; j < G.vexnum; j++) //分别与前面的已着色快进行比较
if (G.arcs[i][j] == 1 && color[i] == color[j])
return 0; //发生冲突
return 1;
}
void GAColorGraph(ALGraph& G) //贪心法求解图着色
{
cout << "*************(贪心法)开始着色*************" << endl;
int k = 0, flag = 1, n = G.vexnum;
while (flag == 1)
{
k++; flag = 0;
for (int i = 0; i < n; i++)
{
if (color[i] == 0)
{
color[i] = k;
if (!Ok(G, i))
color[i] = 0; flag = 1;
}
}
}
}
void BTColorGraph(ALGraph& G, int m) //回溯法求解图着色
{
cout << "*************(回溯法)开始着色*************" << endl;
int i, k, n = G.vexnum;
for (i = 0; i < n; i++) //将数组color[n]初始化为0
color[i] = 0;
k = 0;
while (k >= 0)
{
color[k] = color[k] + 1; //取下一种颜色
while (color[k] <= m)
if (Ok(G, k)) break;
else color[k] = color[k] + 1; //搜索下一个颜色
if (color[k] <= m && k == n - 1) //求解完毕,退出循环去打印结果
break;
if (color[k] <= m && k < n - 1)
k = k + 1; //处理下一个顶点
else
color[k--] = 0; //回溯到上一个顶点
}
}
void Stringsplit(const string& str, const string& split, vector<string>& res)//使用正则分割字符串
{
std::regex reg(split); // 匹配split
std::sregex_token_iterator pos(str.begin(), str.end(), reg, -1); //第四个参数为-1时,表明该迭代器不会匹配所有捕捉组内的内容,不处理中间的空格
decltype(pos) end; // 自动推导类型(选择并返回操作数的数据类型)
for (; pos != end; ++pos)
{
res.push_back(pos->str()); //往res数组里加入分割后的字串
}
}
void print(ALGraph& G, int choice)
{
cout << "着色结果如下:" << endl;
if (choice == 1)
{
for (int i = 0; i < G.vexnum; i++)
cout << "点" << G.vexs[i] << "着色:" << color_word[color[i] - 1] << endl;
}
else
{
for (int i = 0; i < G.vexnum; i++)
cout << "点" << G.vexs[i] << "着色:" << color[i] << endl;
}
}
int main()
{
//计时模块所需代码
double run_time = 0; //程序运行时间
//计时所需的相关变量
LARGE_INTEGER start_time; //开始时间
LARGE_INTEGER end_time; //结束时间
double dqFreq; //计时器频率
LARGE_INTEGER freq; //计时器频率
QueryPerformanceFrequency(&freq);
dqFreq = (double)freq.QuadPart;
cout << "请选择着色算法(1 贪心法; 2 回溯法):";
int choice;
cin >> choice;
if (choice == 1)
{
vector<string> strList; // strList接收子串
string str;
int i = 0;
cout << "请输入颜色(例如:红 蓝 绿):";
int r = getchar();
getline(cin, str); //接收带空格输入
Stringsplit(str, " ", strList);
for (auto s : strList) {
color_word[i] = s; //string转int
i++;
}
ALGraph G; //定义无向图G
CreateUDG(G); //创建无向图G
QueryPerformanceCounter(&start_time); //计时开始
GAColorGraph(G); //贪心法着色
QueryPerformanceCounter(&end_time); //计时结束
print(G, 1); //打印结果
run_time = (end_time.QuadPart - start_time.QuadPart) / dqFreq; //计时时间计算
cout << "\n贪心法耗时:" << run_time * 1000.0 * 1000.0 << "皮秒" << endl;
}
else if (choice == 2)
{
cout << "请设定颜色的最大总数:";
int m;
cin >> m;
ALGraph G; //定义无向图G
CreateUDG(G); //创建无向图G
QueryPerformanceCounter(&start_time); //计时开始
BTColorGraph(G, m); //回溯法着色
QueryPerformanceCounter(&end_time); //计时结束
print(G, 2); //打印结果
run_time = (end_time.QuadPart - start_time.QuadPart) / dqFreq; //计时时间计算
cout << "\n回溯法耗时:" << run_time * 1000.0 * 1000.0 << "皮秒" << endl;
}
cout << endl;
int r = getchar();
return 0;
}