📜  门| GATE CS 1997 |问题28(1)

📅  最后修改于: 2023-12-03 15:42:10.701000             🧑  作者: Mango

门 | GATE CS 1997 | 问题28

本题需求考生查找到一个连通图中的割点,需要编写一个程序实现该任务。

问题描述

给定一个连通无向图 $G=(V,E)$,其中 $V$ 表示节点集合,$E$ 表示边集合。一个节点 $v\in V$ 被称为割点,当且仅当将它从图 $G$ 中移除后,原本连通的图被分割成两个或更多个非空的连通子图。

编写一个程序实现查找 $G$ 中所有的割点,并输出它们的列表。

程序设计

首先,我们需要定义一个结构体表示节点:

struct node {
    int id; /* 节点的编号 */
    int dfs; /* dfs 序号 */
    int low; /* low 的值 */
    int father; /* 父节点的编号 */
    int is_cut; /* 标记是否为割点 */
    int child; /* 孩子节点的数量 */
};

然后,定义一个结构体表示图:

struct graph {
    int vertex_num; /* 节点的数量 */
    int edge_num; /* 边的数量 */
    struct node *nodes; /* 节点列表 */
    int **edges; /* 邻接矩阵 */
};

接下来,我们可以实现一个深搜函数:

void dfs(int id, struct graph *g, int *time) {
    struct node *n = &(g->nodes[id]);
    n->dfs = n->low = ++(*time);
    int i;
    for (i = 0; i < g->vertex_num; i++) {
        if (g->edges[id][i] == 1) {
            struct node *t = &(g->nodes[i]);
            if (t->dfs == 0) {
                t->father = id;
                n->child++;
                dfs(i, g, time);
                if (t->low >= n->dfs) {
                    n->is_cut = 1;
                }
                n->low = min(n->low, t->low);
            } else if (t->id != n->father) {
                n->low = min(n->low, t->dfs);
            }
        }
    }
}

最后,我们可以实现一个主函数,输出图中所有的割点:

void print_cuts(struct graph *g) {
    int i;
    int time = 0;
    for (i = 0; i < g->vertex_num; i++) {
        struct node *n = &(g->nodes[i]);
        if (n->dfs == 0) {
            dfs(i, g, &time);
            if (n->child > 1) {
                n->is_cut = 1;
            }
        }
    }
    printf("The cut points are: ");
    for (i = 0; i < g->vertex_num; i++) {
        struct node *n = &(g->nodes[i]);
        if (n->is_cut == 1) {
            printf("%d ", n->id);
        }
    }
    printf("\n");
}
测试

我们以如下的图为例进行测试:

     0
    / \
   /   \
  1-----2
 /     / \
3     4---5

我们可以编写如下的代码进行测试:

int main() {
    struct graph g;
    g.vertex_num = 6;
    g.edge_num = 7;
    g.nodes = (struct node *)malloc(g.vertex_num * sizeof(struct node));
    g.edges = (int **)malloc(g.vertex_num * sizeof(int *));
    int i, j;
    for (i = 0; i < g.vertex_num; i++) {
        g.edges[i] = (int *)malloc(g.vertex_num * sizeof(int));
        for (j = 0; j < g.vertex_num; j++) {
            g.edges[i][j] = 0;
        }
    }
    for (i = 0; i < g.vertex_num; i++) {
        struct node *n = &(g.nodes[i]);
        n->id = i;
        n->dfs = n->low = n->father = n->is_cut = n->child = 0;
    }
    g.edges[0][1] = g.edges[1][0] = 1;
    g.edges[0][2] = g.edges[2][0] = 1;
    g.edges[1][3] = g.edges[3][1] = 1;
    g.edges[2][4] = g.edges[4][2] = 1;
    g.edges[2][5] = g.edges[5][2] = 1;
    g.edges[4][5] = g.edges[5][4] = 1;
    print_cuts(&g);
    return 0;
}

输出结果如下:

The cut points are: 2
总结

本题需要考生熟练掌握图论中的割点算法,并能够实现深搜和邻接矩阵的数据结构。通过本题的练习可以提高解决复杂问题的能力,使代码具有较强的实用性。