在The Algorithm Design Manual中,作者提供了一种对图进行两种着色的算法。它类似于计算组件数量的算法,因为它迭代所有可用顶点,然后仅在未发现该顶点时对该顶点着色并执行 BFS:
for(i = 1; i <= (g->nvertices); i++) {
if(discovered[i] == FALSE) {
color[i] = WHITE;
bfs(g, i);
}
}
BFS在边缘没有被处理或者图是有向的process_edge
时候调用一个函数。BFS 看起来像这样:y
x -> y
bfs(graph *g, int start) {
queue q; //queue of vertices to visit
int v; //current vertex
int y; //successor vertex
edgenode* p; //temporary pointer used to traverse adjacency list
init_queue(&q);
enqueue(&q, start);
discovered[start] = TRUE;
while(empty_queue(&q) == FALSE) {
v = dequeue(&q);
process_vertex_early(v); //function that handles early processing
processed[v] = TRUE;
p = g->edges[v];
while(p != NULL) {
y = p->y;
//If the node hasn't already been processed, or if the graph is directed
//process the edge. This part bothers me with undirected graphs
//because how would you process an edge that was wrongly colored
//in an earlier iteration when it will have processed[v] set to TRUE?
if((processed[y] == FALSE) || g->directed) {
process_edge(v, y); //coloring happens here
}
if(discovered[y] == FALSE) {
enqueue(&q, y);
discovered[y] = TRUE;
parent[y] = v;
}
p = p->next;
}
process_vertex_late(v); //function that handles late processing
}
}
该process_edge
函数如下所示:
process_edge(int x, int y) {
if(color[x] == color[y]) {
bipartite = FALSE;
printf("Warning: not bipartite due to (%d, %d)\n", x, y);
}
color[y] = complement(color[x]);
}
现在假设我们有一个这样的图表:
我们可以像这样对它进行两种着色:
但是,如果我们按顶点顺序遍历它,那么我们最初将从 node 开始1
,并将其着色为WHITE
。然后我们将找到节点13
并将其着色为BLACK
. 在循环的下一次迭代中,我们正在查看5
未发现的节点,因此我们将对其着色WHITE
并在其上启动 BFS。在执行此操作时,我们会发现节点之间存在冲突5
,1
因为1
应该是BLACK
,但之前设置为WHITE
。1
然后我们会发现and之间的另一个冲突13
,因为13
应该是WHITE
,但它被设置为BLACK
。
当通过所有组件(连接或未连接)执行图的正常遍历时,顺序无关紧要,因为无论如何我们最终都会访问所有节点,但是在为图着色的情况下顺序似乎很重要。我没有在书中看到提到这一点,只是在我尝试对上面的随机生成的图形进行双色着色时才遇到这个问题。我能够对现有算法进行一些小改动,从而消除了这个问题:
for(i = 1; i <= (g->nvertices); i++) {
//Only initiate a BFS on undiscovered vertices and vertices that don't
//have parents.
if(discovered[i] == FALSE && parent[i] == NULL) {
color[i] = WHITE;
bfs(g, i);
}
}
这种变化是否有意义,还是因为我不理解一些基本概念而造成的?
更新
根据 G. Bach 的回答,假设我们有以下图表:
我仍然对这将如何正确地变成双色感到困惑。使用原始算法,第一次迭代将启动一个带节点的 BFS,1
为我们提供一个颜色如下的图:
在下一次迭代中,我们将启动一个带节点的 BFS,5
为我们提供一个颜色如下的图:
下一次迭代将启动一个带节点的 BFS,6
为我们提供一个像这样着色的图:
但是现在我们不会重新着色5
,因为我们已经访问过它,所以这给我们留下了一个没有正确着色的图表。