有向无环图两点之间的路径数目(算法导论22.4-2)

来源:互联网 发布:mac 文件锁定 编辑:程序博客网 时间:2024/05/17 02:26

有向无环图G=(V,E),求其点s和e之间的路径数目。此题首先要以点s开始作DFS,得到从s为起点的所有可达点的一顶DFS树,但这个路径数目需要详细参详。

定义P(x),表示点s到点x的路径数目,P(s)=1,即s到自身有一条路径,其余的所有路径数目都初始化为0。

路径从s到达点x,则必须到达x的上一层结点,假设以x为终点的上一层结点有n个,即a1,a2,...,an,由加法定律可知P(x)= P(a1) + P(a2) + ... + P(an),这是一个从顶向下的递推过程,有点类似于动态规划。

综上,我们只要获取任意一点的入邻接表(也称逆邻接表),由图G获取其转置GT,其中保存着任意一点的上一层结点。然后再从顶向下递推,正好利用拓扑排序获得的序列,因为由拓扑排序的定义可以保证结点的顺序关系,因此递推有效。以下的算法步骤:

(1) 由图G获取其转置图GT,以得到所有点的入邻接表

(2) 以点s开始作DFS,得到从点s到达点e的拓扑序列

(3) 以此拓扑序列为顺序,逐个获取P值,最终得到P(e),即s到e的路径数目

 

图中实线为tree edge,曲线为forward和cross edge,从p到v的路径数目,递推过程如下:

P(p) = 1

P(o) = P(p) = 1

P(s) = P(p) + P(o)= 2

P(r) = P(o) +P(s) = 3

P(y) = P(r) = 3

P(v) = P(y) +P(o) = 4

 

步骤(1) 代码如下 

static int graph_add_edge(struct link_graph *G, int uindex, int vindex){    struct link_edge *e = NULL;    struct link_vertex *u = G->v + uindex;    e = malloc(sizeof(struct link_edge));    if (!e)        return -1;    e->vindex = vindex;    e->type = EDGE_NONE;    list_add(&e->node, &u->head);    return 0;}struct link_graph* graph_transpos(struct link_graph *G){    int i = 0;    struct link_edge *e = NULL;    struct link_vertex *u = NULL;    struct link_graph *GT = NULL;    GT = malloc(sizeof(struct link_graph));    if (!GT)        return NULL;    GT->v = malloc(G->vcount * sizeof(struct link_vertex));    if (!GT->v) {        free(GT);        return NULL;    }    GT->vcount = G->vcount;    GT->ecount = G->ecount;    for (i = 0;i < GT->vcount;i++) {        u = GT->v + i;        u->vindex = i;        INIT_LIST_HEAD(&u->head);    }    for (i = 0;i < G->vcount;i++) {        u = G->v + i;        list_for_each_entry(e, &u->head, node) {            graph_add_edge(GT, e->vindex, i);        }    }    return GT;}

步骤(2) 代码如下 

void DFS_visit_topo(struct link_graph *G, struct link_vertex *u, int *color, struct list_head *head){    struct link_edge *le = NULL;        color[u->vindex] = COLOR_GRAY;    list_for_each_entry(le, &u->head, node) {        if (color[le->vindex] == COLOR_WHITE) {            DFS_visit_topo(G, G->v + le->vindex, color, head);            le->type = EDGE_TREE;        }        else if (color[le->vindex] == COLOR_GRAY) {            le->type = EDGE_BACK;            printf("G has cycle and cannot topology sort\n");        }    }        color[u->vindex] = COLOR_BLACK;    list_add(&u->qnode, head);}int graph_topo_sort(struct link_graph *G, int s, struct list_head *thead){    int i;    int *color;    color = malloc(sizeof(int) * G->vcount);    for (i = 0;i < G->vcount;i++) {        color[i] = COLOR_WHITE;    }    DFS_visit_topo(G, G->v + s, color, thead);    free(color);    return 0;}

步骤(3) 代码如下 

int graph_count_path(struct link_graph *G, int s, int end){    int *P;    struct list_head thead;    struct link_vertex *u = NULL, *ut = NULL;    struct link_edge *e = NULL;    struct link_graph *GT = NULL;    GT = graph_transpos(G);    if (GT == NULL)        return -1;    P = malloc(G->vcount * sizeof(int));    memset(P, 0, G->vcount * sizeof(int));    P[s] = 1;    INIT_LIST_HEAD(&thead);    graph_topo_sort(G, s, &thead);    printf("The topology sort from %d is below:\n", s);    list_for_each_entry(u, &thead, qnode) {        printf("%4d ", u->vindex);        if (u->vindex == s)            continue;        ut = GT->v + u->vindex;        list_for_each_entry(e, &ut->head, node) {            P[u->vindex] += P[e->vindex];        }        if (u->vindex == end) {            printf("\n\nThere are %d paths from %d to %d\n", P[end], s, end);            break;        }    }    link_graph_exit(GT);    return 0;}

原创粉丝点击