• tarjan算法——点双连通分量


    简介:用tarjan找割点,当dfn[u]<=low[v]时,证明当前的u为割点,注意割点可能存在于多个点双连通分量中,所以存点的时候要格外注意。如果当前遍历到的v已在栈中,可以用dfn[v]更新low[u]。

      ps:两点一边的图也为一个点双连通分量。

    模板:

      将下面的代码略微改动即可

    例题:

      hduoj3394  Railway

     1 #include<iostream>
     2 #include<cstdio>
     3 #include<cctype>
     4 #include<vector>
     5 #define numm ch-48
     6 #define pd putchar(' ')
     7 #define pn putchar('
    ')
     8 #define pb push_back
     9 #define debug(args...) cout<<#args<<"->"<<args<<endl
    10 #define bug cout<<"************"
    11 using namespace std;
    12 template <typename T>
    13 void read(T &res) {
    14     bool flag=false;char ch;
    15     while(!isdigit(ch=getchar())) (ch=='-')&&(flag=true);
    16     for(res=numm;isdigit(ch=getchar());res=(res<<1)+(res<<3)+numm);
    17     flag&&(res=-res);
    18 }
    19 template <typename T>
    20 void write(T x) {
    21     if(x<0) putchar('-'),x=-x;
    22     if(x>9) write(x/10);
    23     putchar(x%10+'0');
    24 }
    25 typedef long long ll;
    26 const int maxn=10010;
    27 const int maxm=200010;
    28 const ll mod=1e9+7;
    29 int low[maxn],dfn[maxn],sta[maxn],vis[maxn],sum,head[maxn],f[maxn];
    30 int u[maxm],v[maxm];
    31 int n,m,lay,ans1,ans2,cnt;
    32 struct node {
    33     int net,v;
    34     node(){}
    35     node(int v,int net):v(v),net(net){}
    36 }e[maxm];
    37 void add(int u,int v) {
    38     e[++cnt]=node(v,head[u]);
    39     head[u]=cnt;
    40 }
    41 void getnode(int sccnum) {
    42     int cnt=0;
    43     for(int i=1;i<=m;i++)
    44         if(f[u[i]]==sccnum&&f[u[i]]==f[v[i]])
    45             cnt++;
    46     if(cnt>=sum) ans1+=cnt;  ///当中没有桥
    47     if(cnt>sum) ans2+=cnt;
    48 }
    49 void tarjan(int x,int &sccnum) {
    50     sta[++cnt]=x;
    51     low[x]=lay;
    52     dfn[x]=lay++;
    53     vis[x]=1;
    54     for(int i=head[x];~i;i=e[i].net) {
    55         int v=e[i].v;
    56         if(!dfn[v]) {
    57             tarjan(v,sccnum);
    58             low[x]=min(low[x],low[v]);
    59             if(dfn[x]<=low[v]) {    ///x是割点
    60                 ++sccnum;
    61                 sum=0;  ///点的数量
    62                 do {
    63                     f[sta[cnt]]=sccnum;
    64                     vis[sta[cnt]]=2;
    65                     sum++;
    66                 }while(sta[cnt--]!=v);
    67                 f[x]=sccnum,sum++;
    68                 getnode(sccnum);
    69             }
    70         }
    71         else if(vis[v]==1) low[x]=min(low[x],dfn[v]);
    72     }
    73 }
    74 int main()
    75 {
    76 
    77     while(scanf("%d%d",&n,&m)!=EOF&&(n+m)) {
    78         ans1=ans2=0;
    79         for(int i=0;i<n;i++)
    80             head[i]=-1,vis[i]=0,dfn[i]=0,f[i]=0;
    81         cnt=0;
    82         for(int i=1;i<=m;i++) {
    83             read(u[i]),read(v[i]);
    84             add(u[i],v[i]);
    85             add(v[i],u[i]);
    86         }
    87         lay=1,cnt=0;
    88         int sccnum=0;
    89         for(int i=0;i<n;i++)
    90             if(!vis[i]) tarjan(i,sccnum);
    91         write(m-ans1),pd,write(ans2);pn;
    92     }
    93     return 0;
    94 }
    View Code
  • 相关阅读:
    LeetCode--Array--Two sum (Easy)
    LeetCode--Unique Email Addresses & Hamming Distance (Easy)
    LeetCode--Squares of a Sorted Array && Robot Return to Origin (Easy)
    LeetCode--Sort Array By Parity && N-Repeated Element in Size 2N Array (Easy)
    LeetCode 11月第1周题目汇总
    LeetCode 十月份题目汇总
    【每天一题】LeetCode 172. 阶乘后的零
    【每天一题】LeetCode 121. 买卖股票的最佳时机
    【每天一题】LeetCode 0107. 自底向上层遍历二叉树
    【每天一题】LeetCode 0067. 二进制求和
  • 原文地址:https://www.cnblogs.com/wuliking/p/11514857.html
Copyright © 2020-2023  润新知