【割点】UVA - 315 Network

本文介绍了一种求解无向图中割点数量的算法。通过使用num[]和low[]数组来跟踪节点的时间戳,利用深度优先搜索(DFS)遍历图结构,以此判断哪些节点为割点。割点是指移除后会导致图不连通的节点。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

Problem Decription

很裸的求割点 个数的题目。第一行给你n,代表该图有n个点。接下来每行给你一个u,u == 0退出循环,给你很多v,代表u到v有一条无向边。

思路:num[]数组记录该点第几个走到(num[]值是不变的),low[]值是不断更新的,最开始等于num[]值,找到祖先了也就是更小的num[]的时候就更新。回溯的时候和孩子的low[]值比较更新,因为孩子能到的地方,父亲也能到,如果不能回到祖先,就代表有割点也就是low[v] >= num[u],u就是割点。不连通的孩子个数大于一个,也代表父亲是割点

#include<bits/stdc++.h>
using namespace std;
#define mm 105
struct node
{
    int to, next;
};
node Map[mm * mm];
int low[mm], num[mm];//low改变,num不变,都是记录时间戳
int head[mm], flag[mm];//flag[]用来标记那个点是割点
int n, root, sig;
void add(int u, int v, int &cnt)//前向星存图
{
    Map[cnt].to = v;
    Map[cnt].next = head[u];
    head[u] = cnt++;
}
void dfs(int u, int father)
{
    int son = 0;
    low[u] = num[u] = sig++;//一开始low == num
    for(int i = head[u]; ~i; i = Map[i].next)
    {
        int to = Map[i].to;
        if(!num[to])
        {
            son++;
            dfs(to, u);
            low[u] = min(low[to], low[u]);//回溯的时候,更新low[u]的值,因为孩子能到的,父亲都能到
            if(u != root && low[to] >= num[u]){//回不到祖先,代表u是割点
                flag[u] = 1;
            }
            if(u == root && son > 1)//不连通孩子数大于1
            {
                flag[u] = 1;
            }
        }
        else if(to != father)//更新low[]值
        {
            low[u] = min(low[u], num[to]);
        }
    }
    return ;
}
int main()
{
    char c;
    int cnt, u, v;
    while(~scanf("%d", &n) && n)
    {
        cnt = 0;//初始化
        memset(head, -1, sizeof(head));
        memset(num, 0, sizeof(num));
        memset(low, 0, sizeof(low));
        memset(flag, 0, sizeof(flag));
        while(~scanf("%d", &u) && u)//存图
        {
            while(~scanf("%d%c", &v, &c))
            {
                add(u, v, cnt);
                add(v, u, cnt);
                if(c == '\n') break;
            }
        }
        sig = 1;//初始化
        root = 1;
        dfs(1, root);
        int ans = 0;
        for(int i = 1; i <= n; i++)//割点数
        {
            if(flag[i]) ans++;
        }
        printf("%d\n", ans);
    }
    return 0;
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值