(割点)Network

博客内容介绍了图论中的割点定义,强调了割点在图中扮演的角色,特别是对于树结构,割点可能是拥有多个子树的根节点或者在特定父子边连接下满足特定条件的非根节点。

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

题意为求出所给图的割点
割点:一个顶点u是割点,当且仅当满足(1)或(2) :(1) u为树根,且u有多于一个子树。(2) u不为树根,且满足存在(u,v)为树枝边(或称父子边,即u为v在搜索树中的父亲),使得dfn(u)<=Low(v)

#include <set>
#include <cmath>
#include <stack>
#include <vector>
#include <string>
#include <cstdlib>
#include <cstring>
#include <iostream>
#include <algorithm>
using namespace std;
const int maxn = 1e4 + 5;
const int maxm = 1e5 + 5;
struct Edge {
    int to, nxt;
    bool cut; //是否为桥的标记
    Edge() {}
    Edge(int _to, int _nxt, bool _cut) : to(_to), nxt(_nxt), cut(_cut) {}
} edge[maxm];
int head[maxn], tot;
int low[maxn], dfn[maxn], Stack[maxn];
int Index, top;
bool Instack[maxn];
bool cut[maxn];
int add_block[maxn];
int bridge;

void addedge(int u, int v) {
    edge[tot] = Edge(v, head[u], false);
    head[u] = tot++;
}

void Tarjan(int u, int pre) {
    int v;
    low[u] = dfn[u] = ++Index;
    Stack[top++] = u;
    Instack[u] = true;
    int son = 0;
    for(int i = head[u]; i != -1; i = edge[i].nxt) {
        v = edge[i].to;
        if(v == pre) continue;
        if(!dfn[v]) {
            son++;
            Tarjan(v, u);
            if(low[u] > low[v]) low[u] = low[v];
            if(low[v] > dfn[u]) {
                bridge++;
                edge[i].cut = true;
                edge[i ^ 1].cut = true;
            }
            if(u != pre && low[v] >= dfn[u]) {
                cut[u] = true;
                add_block[u]++;
            }
        }
        else if(low[u] > dfn[v]) 
            low[u] = dfn[v];
    }
    if(u == pre && son > 1) cut[u] = true;
    if(u == pre) add_block[u] = son - 1;
    Instack[u] = false;
    top--;  
}

void solve(int n) {
    memset(dfn, 0, sizeof(dfn));
    memset(Instack, false, sizeof(Instack));
    memset(add_block, 0, sizeof(add_block));
    memset(cut, false, sizeof(cut));
    Index = top = 0;
    bridge = 0;
    for(int i = 1; i <= n; ++i)
        if(!dfn[i]) Tarjan(i, i);
    int ans = 0;
    for(int i = 1; i <= n; ++i)
        if(cut[i]) ans++;
    printf("%d\n", ans);
}
void init() {
    tot = 0;
    memset(head, -1, sizeof(head));
}
int g[110][110];
int main()
{
    int n;
    while(scanf("%d", &n) && n) {
        int u, v;
        char op;
        memset(g, 0, sizeof(g));
        while(~scanf("%d", &u) && u) {
            while(~scanf("%d%c", &v, &op)) {
                g[u][v] = g[v][u] = 1;
                if(op == '\n') break;
            }
        }
        init();
        for(int i = 1; i <= n; ++i) 
            for(int j = i + 1; j <= n; ++j)
                if(g[i][j]) {
                    addedge(i, j);
                    addedge(j, i);
                }
        solve(n);
    }
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值