Template

【题目描述】

给定一个无向图,询问图中存在多少个割点。

【输入描述】

第一行输入两个正整数N、M(N,M <= 50000),表示顶点数目和边数目;

接下来M行,每行输入两个整数A、B,表示顶点A、B之间存在一条双向边。

【输出描述】

输出一个非负整数,表示答案。

【输入样例】

4 4

1 2

2 3

3 4

2 4

【输出样例】

1

源代码:

#include<cstdio>
#include<algorithm>
using namespace std;
struct Node
{
    int To,Next;
}Edge[100001]; //二倍大。
int m,n,Sum(0),Num(0),Ans(0),i[50001],j[50001],Head[50001];
bool Cut[50001];
void Add(int t1,int t2) //边表。
{
    Edge[++Sum].To=t2;
    Edge[Sum].Next=Head[t1];
    Head[t1]=Sum;
}
void Tarjan(int t,int Father) //Tarjan求桥割类。
{
    int S(0);
    i[t]=j[t]=++Num;
    for (int a=Head[t];a;a=Edge[a].Next)
    {
        int T=Edge[a].To;
        if (!j[T])
        {
            S++;
            Tarjan(T,t);
            i[t]=min(i[t],i[T]);
            if (i[T]>=j[t]) //翻不到上方又是直连边,显而易见为割。
              Cut[t]=true; //仔细想一下,为什么给Cut[t]赋值而不是Cut[T]。
        }
        else
          if (T!=Father)
            i[t]=min(i[t],j[T]);
    }
    if (S==1&&!Father) //防止两点的无效重复环。
      Cut[t]=false;
}
int main() //裸Tarjan求割点。
{
    scanf("%d%d",&n,&m);
    for (int a=1;a<=m;a++)
    {
        int t1,t2;
        scanf("%d%d",&t1,&t2);
        Add(t1,t2);
        Add(t2,t1);
    }
    for (int a=1;a<=n;a++)
      if (!j[a])
        Tarjan(a,0);
    for (int a=1;a<=n;a++)
      if (Cut[a])
        Ans++;
    printf("%d",Ans);
    return 0;
}
原文地址:https://www.cnblogs.com/Ackermann/p/6005538.html