Welch Powell 算法其实就是在进行贪心算法之前先对节点排了下序,具体过程如下:
(1) 将图 G 中的节点按度数的递减顺序进行排列(这种排列可能不是唯一的,因为有些节点的度数可能相同)
(2) 用第一种颜色对第一个节点着色,并按排列顺序对与前面着色节点不邻接的每一节点着上同样的颜色
(3) 用第二种颜色对尚未着色的节点重复步骤 (2),用第三种颜色继续这种做法,直到所有的节点全部着上色为止
具体实例网上有很多,我就不赘述了。
不过实现算法却很少,我主要参考了这篇博文里的代码,并做了一些修改。这篇博文里的代码逻辑是有点问题的,就是在节点排序前后有一些变量已经跟原先不对应了,所以需要相应地做些调整;但其代码结构还是很值得借鉴的,所以我继续沿用了这种风格。
#include <stdio.h>
#include <algorithm>
#define MAX 100
using namespace std;
int c[MAX][MAX];
int n;
struct Vertex
{
int color;
int degree;
int flag; // 标记原始点的位置
} vertex[MAX];
// 排序前的副本
Vertex copys[MAX];
// 初始化顶点颜色,并计算每个点的度数
void getDegree()
{
for(int i = 1; i <= n; i++)
{
vertex[i].color = vertex[i].degree = 0;
vertex[i].flag = i;
for(int j = 1; j <= n; j++)
vertex[i].degree += c[i][j];
}
}
// 按顶点度数从大到小排序
bool cmp(Vertex a, Vertex b)
{
return a.degree > b.degree;
}
int main()
{
printf("输入顶点数:");
scanf("%d", &n);
printf("输入无向图的邻接矩阵:\n");
for(int i = 1; i <= n; i++)
for(int j = 1; j <= n; j++)
scanf("%d", &c[i][j]);
getDegree();
// 排序前保留一份副本
for(int i = 1; i <= n; i++) {
copys[i].color = 0;
copys[i].degree = vertex[i].degree;
copys[i].flag = vertex[i].flag;
}
sort(vertex + 1, vertex + n + 1, cmp);
int coloredNum = 0;
int k = 0;
while(coloredNum < n)
{
k++;
for(int i = 1; i <= n; i++)
{
// 如果没有着色
if(vertex[i].color == 0)
{
bool ok = true;
for(int j = 1; j <= n; j++)
{
// 如果相邻顶点有相同颜色
if(c[vertex[i].flag][j] == 1 && copys[j].color == k)
{
ok = false;
break;
}
}
// 相邻顶点有相同颜色,直接跳过
if(!ok)
continue;
// 相邻顶点没有相同颜色,则对当前节点着色
vertex[i].color = copys[vertex[i].flag].color = k;
coloredNum++;
printf("顶点 %d 着色为 %d\n", vertex[i].flag, vertex[i].color);
}
}
}
printf("共需 %d 种颜色\n", k);
}
例如,给此图着色(字母顺序对应数字顺序)
运行结果如下: