Proving Equivalences HDU-2767 (tarjan縮點)
阿新 • • 發佈:2020-08-25
Practice link: HDU-2767
題意:給你一張有向圖,問你最少需要增加幾條邊整張圖變成一個強連通分量。
思路:首先我們把整張圖已有的邊來找到現有的圖有的強連通分量,然後進行縮點,然後去得到每個強連通分量的入度和出度,要讓整張圖聯通,只需要讓所有強連通分量連成一個環即可,因此考慮 max( 入度為0的點 ,出度為0的點)即可。
注意點是當現有圖只有一個強連通分量是,直接輸出0。
程式碼:
1 //#include<bits/stdc++.h> 2 #include<cstdio> 3 #include<cstring> 4 #include<algorithm> 5#include<iostream> 6 #include<string> 7 #include<vector> 8 #include<stack> 9 #include<bitset> 10 #include<cstdlib> 11 #include<cmath> 12 #include<set> 13 #include<list> 14 #include<deque> 15 #include<map> 16 #include<queue> 17#define ll long long 18 #define MOD 1000000007 19 #define INF 0x3f3f3f3f 20 #define mem(a,x) memset(a,x,sizeof(a)) 21 #define lowbit(x) x&(-x) 22 #define ios ios::sync_with_stdio(false);cin.tie(0);cout.tie(0); 23 using namespace std; 24 int dfn[50005]; 25 int low[50005]; 26 int vis[50005]; 27 int stacks[50005]; 28 int color[50005]; 29 int cnt[50005]; 30 int deep,sum,top; 31 int n,m; 32 vector<int>g[50005]; 33 void tarjan(int u) 34 { 35 dfn[u]=++deep; 36 low[u]=deep; 37 vis[u]=1; 38 stacks[++top]=u; 39 for(int i=0;i<g[u].size();i++){ 40 int v=g[u][i]; 41 if(!dfn[v]) 42 { 43 tarjan(v); 44 low[u]=min(low[u],low[v]); 45 }else{ 46 if(vis[v]){ 47 low[u]=min(low[v],low[u]); 48 } 49 } 50 } 51 if(dfn[u]==low[u]) 52 { 53 color[u]=++sum; 54 vis[u]=0; 55 while(stacks[top]!=u) 56 { 57 color[stacks[top]]=sum; 58 vis[stacks[top--]]=0; 59 } 60 top--; 61 } 62 } 63 //tarjan 部分 64 int T; 65 int in[20005],out[20005]; 66 int main() 67 { 68 int T; 69 cin>>T; 70 while(T--){ 71 deep=0; 72 top=0; 73 sum=0; 74 scanf("%d %d",&n,&m); 75 for(int i=0;i<=n;i++){ 76 g[i].clear(); 77 dfn[i]=0; 78 vis[i]=0; 79 cnt[i]=0; 80 in[i]=0; 81 out[i]=0; 82 } 83 for(int i=1;i<=m;i++){ 84 int from,to; 85 scanf("%d %d",&from,&to); 86 g[from].push_back(to); 87 } 88 for(int i=1;i<=n;i++){ 89 if(!dfn[i]){ 90 tarjan(i); 91 } 92 } 93 for(int i=1;i<=n;i++){ 94 for(auto v:g[i]){ 95 if(color[i]!=color[v]){ 96 out[color[i]]++; 97 in[color[v]]++; 98 } 99 } 100 } 101 int temp1=0,temp2=0; 102 for(int i=1;i<=sum;i++){ 103 if(in[i]==0)temp1++; 104 if(out[i]==0)temp2++; 105 } 106 if(sum==1){ 107 printf("0\n"); 108 }else{ 109 printf("%d\n",max(temp1,temp2)); 110 } 111 112 113 } 114 return 0; 115 }