LA 4287 等价性证明(强连通分量缩点)

https://vjudge.net/problem/UVALive-4287

题意:

给出n个结点m条边的有向图,要求加尽量少的边,使得新图强连通。

思路:
强连通分量缩点,然后统计缩点后的图的每个结点是否还需要出度和入度。

  1 #include<iostream>
  2 #include<algorithm>
  3 #include<cstring>
  4 #include<cstdio>
  5 #include<sstream>
  6 #include<vector>
  7 #include<stack>
  8 #include<queue>
  9 #include<cmath>
 10 #include<map>
 11 #include<set>
 12 using namespace std;
 13 typedef long long ll;
 14 typedef pair<int,ll> pll;
 15 const int INF = 0x3f3f3f3f;
 16 const int maxn=20000+5;
 17 
 18 int n, m;
 19 int tot;
 20 int dfs_clock;
 21 int scc_cnt;
 22 int in[maxn];
 23 int out[maxn];
 24 int pre[maxn];
 25 int head[maxn];
 26 int sccno[maxn];
 27 int lowlink[maxn];
 28 
 29 stack<int> S;
 30 
 31 struct node
 32 {
 33     int v;
 34     int next;
 35 }e[50000+5];
 36 
 37 void addEdge(int u, int v)
 38 {
 39     e[tot].v=v;
 40     e[tot].next=head[u];
 41     head[u]=tot++;
 42 }
 43 
 44 void dfs(int u)
 45 {
 46     pre[u]=lowlink[u]=++dfs_clock;
 47     S.push(u);
 48     for(int i=head[u];i!=-1;i=e[i].next)
 49     {
 50         int v=e[i].v;
 51         if(!pre[v])
 52         {
 53             dfs(v);
 54             lowlink[u]=min(lowlink[u],lowlink[v]);
 55         }
 56         else if(!sccno[v])
 57         {
 58             lowlink[u]=min(lowlink[u],pre[v]);
 59         }
 60     }
 61 
 62     if(lowlink[u]==pre[u])
 63     {
 64         scc_cnt++;
 65         for(;;)
 66         {
 67             int x=S.top();S.pop();
 68             sccno[x]=scc_cnt;
 69             if(x==u)  break;
 70         }
 71     }
 72 }
 73 
 74 
 75 void find_scc()
 76 {
 77     dfs_clock=scc_cnt=0;
 78     memset(sccno,0,sizeof(sccno));
 79     memset(pre,0,sizeof(pre));
 80     for(int i=1;i<=n;i++)
 81     {
 82         if(!pre[i])  dfs(i);
 83     }
 84 }
 85 
 86 int main()
 87 {
 88     //freopen("in.txt","r",stdin);
 89     int T;
 90     scanf("%d",&T);
 91     while(T--)
 92     {
 93         scanf("%d%d",&n,&m);
 94         tot=0;
 95         memset(head,-1,sizeof(head));
 96         while(m--)
 97         {
 98             int u,v;
 99             scanf("%d%d",&u,&v);
100             addEdge(u,v);
101         }
102         find_scc();
103         for(int i=1;i<=scc_cnt;i++)   in[i]=out[i]=1;
104         for(int u=1;u<=n;u++)
105         {
106             for(int i=head[u];i!=-1;i=e[i].next)
107             {
108                 int v=e[i].v;
109                 if(sccno[u]!=sccno[v])  in[sccno[v]]=out[sccno[u]]=0;  //u,v是桥,所以v不需要入度,u不需要出度
110             }
111         }
112 
113 
114         int a=0,b=0;
115         for(int i=1;i<=scc_cnt;i++)
116         {
117             if(in[i])  a++;
118             if(out[i]) b++;
119         }
120         int ans=max(a,b);
121         if(scc_cnt==1)  ans=0;
122         printf("%d
",ans);
123     }
124     return 0;
125 }
原文地址:https://www.cnblogs.com/zyb993963526/p/7294513.html