UVA ~ 315 ~ Network (割点)

在这里插入图片描述

题意

给你一张图,求割点个数。

思路

割点也叫割顶。
①根节点有两个及以上的就是割点。
②如果有一条边u->v,且LOW[v] >= DFN[u],那么u就是割点。

#include <bits/stdc++.h>
using namespace std;
const int MAXN = 1e5 + 5;

struct Edge
{
    int from, to;
    Edge (int from, int to): from(from), to(to) {}
};
struct VertexBCC//点双连通
{
    //有无重边无影响
    int n, m;
    int DFN[MAXN], iscut[MAXN], bccno[MAXN], dfs_clock, bcc_cnt;
    vector<Edge> edges;
    vector<int> G[MAXN], bcc[MAXN];
    stack<Edge> S;
    void init(int n)
    {
        this->n = n, m = 0;
        edges.clear();
        for (int i = 0; i < n; i++) G[i].clear();
    }
    void AddEdge (int from, int to) 
    { 
        edges.push_back(Edge(from, to));
        edges.push_back(Edge(to, from));
        m = edges.size();
        G[from].push_back(m-2);
        G[to].push_back(m-1);
    }
    int dfs(int u, int fa)
    {
        int lowu = DFN[u] = ++dfs_clock;
        int child = 0;
        for (int i = 0; i < G[u].size(); i++)
        {
            Edge e = edges[G[u][i]];
            int v = e.to;
            if (!DFN[v])//没有访问过v
            {
                S.push(e);
                child++;
                int lowv = dfs(v, u);
                lowu = min(lowu, lowv); //用后代的low函数更新自己
                if (lowv >= DFN[u])
                {
                    iscut[u] = true;
                    bcc_cnt++; bcc[bcc_cnt].clear(); //注意!bcc从1开始编号
                    while (1)
                    {
                        Edge x = S.top(); S.pop();
                        if (bccno[x.from] != bcc_cnt)
                            bcc[bcc_cnt].push_back(x.from), bccno[x.from] = bcc_cnt;
                        if (bccno[x.to] != bcc_cnt)
                            bcc[bcc_cnt].push_back(x.to), bccno[x.to] = bcc_cnt;
                        if (x.from == u && x.to == v) break;
                    }
                }
            }
            else if (DFN[v] < DFN[u] && v != fa)
            {
                S.push(e);
                lowu = min(lowu, DFN[v]); //用返祖边更新自己
            }
        }
        if (fa < 0 && child == 1) iscut[u] = 0;
        return lowu;
    }
    void find_bcc()
    {
        //调用结束后s保证为空,所以不用清空
        memset(DFN, 0, sizeof(DFN));
        memset(iscut, 0, sizeof(iscut));
        memset(bccno, 0, sizeof(bccno));
        dfs_clock = bcc_cnt = 0;
        for (int i = 0; i < n; i++)
            if (!DFN[i]) dfs(i, -1);
    }
}gao;

int n;
int main()
{
    while (~scanf("%d", &n) && n)
    {
        gao.init(n);
        int u, v;
        char c;
        while (~scanf("%d", &u) && u)
        {
            u--;
            while (~scanf("%d%c", &v, &c))
            {
                v--;
                gao.AddEdge(u , v);
                if (c == '\n') break;
            }
        }
        gao.find_bcc();
        int ans = 0;
        for (int i = 0; i < n; i++)
        {
            if (gao.iscut[i]) ans++;
        }
        printf("%d\n", ans);
    }
    return 0;
}
/*
5
5 1 2 3 4
0
6
2 1 3
5 4 6 2
0
0
*/

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值