Algorithm 当尝试对有向图进行二次着色时,顶点顺序是否重要?

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) {

在本文中,作者给出了图的二次着色算法。它类似于计算组件数量的算法,因为它迭代所有可用顶点,然后仅在未发现该顶点时对该顶点着色并执行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) {

    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算法。我将在稍后发布。