在The Algorithm Design Manual中,作者提供了一种对图形进行双色着色的算法。它类似于计算组件数量的算法,因为它迭代所有可用的顶点,然后只有在没有被发现的情况下颜色并在该顶点上执行BFS:
for(i = 1; i <= (g->nvertices); i++) {
if(discovered[i] == FALSE) {
color[i] = WHITE;
bfs(g, i);
}
}
如果未处理边process_edge
中的y
,或者图表是定向的,则BFS会调用x -> y
函数。 BFS看起来像这样:
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]);
}
现在假设我们有一个这样的图表:
我们可以这样双色:
但是如果我们按顶点顺序遍历它,那么我们最初将从节点1
开始,并将其颜色设置为WHITE
。然后我们会找到节点13
并将其颜色设置为BLACK
。在循环的下一次迭代中,我们正在查看未被发现的节点5
,因此我们将对其进行着色WHITE
并在其上启动BFS。执行此操作时,我们会发现节点5
和1
之间存在冲突,因为1
应为BLACK
,但之前已设置为WHITE
。然后,我们会发现1
和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的answer,假设我们有以下图表:
我仍然感到困惑的是如何才能最终成为双色的。使用原始算法,第一次迭代将启动一个带有节点1
的BFS,为我们提供一个颜色如下的图:
在下一次迭代中,我们将启动一个带有节点5
的BFS,为我们提供一个颜色如下的图:
下一次迭代将启动一个带有节点6
的BFS,为我们提供一个颜色如下的图表:
但是现在我们不会重新着色5
,因为我们已经访问了它,所以这给我们留下了一个没有正确着色的图表。
答案 0 :(得分:1)
图的指向性质与您提出的二分着色问题无关,除非您定义一个方向确实开始重要的不同问题。因此,您可以将示例中使用的图形转换为无向图,并运行教科书中给出的算法。
虽然教科书没有明确提到图形应该是无向的,但边缘方向与我们研究的常见着色问题无关。但是,您可以定义考虑边缘方向的问题(http://www.labri.fr/perso/sopena/pmwiki/index.php?n=TheOrientedColoringPage.TheOrientedColoringPage)。
注意:我打算把它写成评论,但作为一个新手,我不允许这样做,直到我积累了一些声望点。
答案 1 :(得分:0)
使用BFS对二分图着色不依赖于顶点顺序。调用构成二分图A和B的分区的两个顶点集; WLOG从A中的顶点a
开始,将其颜色为白色;第一个BFS将找到邻居N(a)
,它们都将被着色为黑色。对于包含所有v in N(a)
的每个v in B
,这将启动BFS(如果我正确读取),再次查找N(v)
A
的子集,将它们全部着色白色等等。
如果你尝试使用这个不是二分图的颜色,你会遇到一个奇数长度的循环(因为像子图这样的循环相当于不是二分)并且BFS在某些时候会遇到再次开始该奇数周期的顶点并发现它已经有颜色,但不是它想要分配给它的颜色。
我认为你的图表会发生什么(因为你从1开始在BFS中不包括5)是指向它的;我假设您读取的算法是针对无向图编写的,否则您会遇到所描述的问题。此外,着色图通常在无向图上定义(当然可以转移到有向图)。
您的修复程序通常无法解决问题;添加新的顶点6
以及边6->24
,您将遇到同样的问题。从5
开始的BFS将要求1
黑色,从6
开始的BFS将要将其着色为白色。但是,该图表仍然是2可着色的。