Algorithm 当尝试对有向图进行二次着色时,顶点顺序是否重要?
在本文中,作者给出了图的二次着色算法。它类似于计算组件数量的算法,因为它迭代所有可用顶点,然后仅在未发现该顶点时对该顶点着色并执行BFS:Algorithm 当尝试对有向图进行二次着色时,顶点顺序是否重要?,algorithm,data-structures,graph,bipartite,graph-coloring,Algorithm,Data Structures,Graph,Bipartite,Graph Coloring,在本文中,作者给出了图的二次着色算法。它类似于计算组件数量的算法,因为它迭代所有可用顶点,然后仅在未发现该顶点时对该顶点着色并执行BFS: for(i = 1; i <= (g->nvertices); i++) { if(discovered[i] == FALSE) { color[i] = WHITE; bfs(g, i); } } process\u edge函数如下所示: bfs(graph *g, int start) {
for(i = 1; i <= (g->nvertices); i++) {
if(discovered[i] == FALSE) {
color[i] = WHITE;
bfs(g, i);
}
}
process\u edge
函数如下所示:
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(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]);
}
现在假设我们有这样一个图:
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(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]);
}
我们可以像这样把它涂成两种颜色:
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(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
开始,并将其着色为白色。然后我们将找到节点13
,并将其颜色设置为黑色。在循环的下一次迭代中,我们将查看未发现的节点5
,因此我们将把它涂成白色
,并在其上启动BFS。执行此操作时,我们将发现节点5
和1
之间存在冲突,因为1
应该是黑色
,但它以前被设置为白色
。然后我们将发现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);
}
}
for(i=1;i n证书);(i++){
//仅在未发现的顶点和未发现的顶点上启动BFS
//我有父母。
if(发现的[i]==FALSE&&parent[i]==NULL){
颜色[i]=白色;
bfs(g,i);
}
}
这种改变有意义吗,还是因为我不理解一些基本概念而造成的
更新
基于G.Bach,假设我们有以下图表:
我仍然很困惑,这将如何结束两个颜色正确。对于原始算法,第一次迭代将启动一个节点为1
的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(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]);
}
在下一次迭代中,我们将启动一个节点为5
的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(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]);
}
下一次迭代将启动节点为6
的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(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]);
}
但是现在我们将不重新着色5
,因为我们已经访问过它,因此这会留下一个没有正确着色的图。使用BFS着色二部图不依赖于顶点顺序。调用构成二部图A和B分区的两个顶点集;WLOG从顶点开始a
在a中,将其涂成白色;第一个BFS将找到邻居N(a)
,它们都将被涂成黑色。对于N(a)
中的每个v以及B中的所有v
,这将启动一个BFS(如果我读得正确的话),再次查找N(v)
,它是a
的子集,将它们全部涂成白色,以此类推
如果您尝试使用此方法为非二部图着色,您将遇到奇数长度的循环(因为将这样的循环作为子图等同于不是二部图),BFS将在某个点再次遇到该奇数循环的起始顶点,并发现它已经有颜色,但不是它想要分配给它的那个
我假设你的图(因为你不包括从1开始的BFS中的5)是有方向的;我假设您阅读的算法是针对无向图编写的,因为否则您会遇到您描述的问题。此外,着色图通常定义在无向图上(当然可以转移到有向图)
您的修复通常不会解决问题;添加一个新的顶点6
以及边6->24
,您将遇到相同的问题。从5
开始的BFS需要将1
涂成黑色,从6
开始的BFS需要将其涂成白色。但是,该图仍然是2-可着色的。该图的有向性质与您提出的二部着色问题无关,除非您定义了一个不同的问题,其中方向确实开始起作用。因此,您可以将示例中使用的图转换为无向图,并运行教科书中给出的算法
虽然教科书没有明确提到图形应该是无向的,但边方向与我们研究的常见着色问题无关。但是,您可以定义考虑边缘方向()的问题
注意:我本打算写这篇评论,但作为一个新手,我不允许这样做,除非我积累了一些信誉点。在所描述的算法的上下文中如何?它会发出虚假的警告,但最终会以一个合法的2色图形结束吗?你能解释一下你的意思吗?我真的不明白那个问题。@GBach,我正在更新这个问题。此外,该算法已定义为有向和无向。至少在书中是这样的。@VivinPaliath我想这本书的那一部分在网上是没有的吧?如果没有太多的页面,也许你可以把它们扫描进来并发给我?我很想提供帮助,但我不知道该算法如何适用于一般的有向图(除非bfs做了意外的事情)。唯一缺少的是bfs算法。我将在稍后发布。