问一个图,最少需要加多少条边,使得这个图强联通。
Tarjan缩点,重建图,令a=入度为0的scc个数,b=出度为0的scc个数,ans=max(a,b);
若图scc=1,本身强联通,ans=0;
1 #include<bits/stdc++.h> 2 using namespace std; 3 const int MAXN = 20010;//点数 4 const int MAXM = 200100;//边数 5 struct Edge { 6 int to,next; 7 }edge[MAXM]; 8 int head[MAXN],tot,a,b; 9 int Low[MAXN],DFN[MAXN],Stack[MAXN],Belong[MAXN];//Belong数组的值是1~scc 10 int Index,top; int scc;//强连通分量的个数 11 int in[MAXN],out[MAXN]; 12 bool Instack[MAXN]; 13 int num[MAXN];//各个强连通分量包含点的个数,数组编号1~scc //num数组不一定需要,结合实际情况 14 15 void addedge(int u,int v){ 16 edge[tot].to = v; 17 edge[tot].next = head[u]; 18 head[u] = tot++; 19 } 20 void Tarjan(int u){ 21 int v; 22 Low[u] = DFN[u] = ++Index; 23 Stack[top++] = u; 24 Instack[u] = true; 25 for(int i = head[u];i != -1;i = edge[i].next) { 26 v = edge[i].to; 27 if( !DFN[v] ){ 28 Tarjan(v); 29 if( Low[u] > Low[v] ) 30 Low[u] = Low[v]; 31 } 32 else if(Instack[v] && Low[u] > DFN[v]) 33 Low[u] = DFN[v]; 34 } 35 if(Low[u] == DFN[u]){ 36 scc++; 37 do{ 38 v = Stack[--top]; 39 Instack[v] = false; 40 Belong[v] = scc; 41 num[scc]++; 42 }while( v != u); 43 } 44 } 45 void find_degree(int u){ 46 int v; 47 for(int i = head[u];i != -1;i = edge[i].next){ 48 v = edge[i].to; 49 if(Belong[u]==Belong[v]) continue; 50 in[Belong[v]]++; 51 out[Belong[u]]++; 52 } 53 } 54 void solve(int N){ 55 memset(DFN,0,sizeof(DFN)); 56 memset(Instack,false,sizeof(Instack)); 57 memset(num,0,sizeof(num)); 58 Index = scc = top = 0; 59 for(int i = 1;i <= N;i++) 60 if(!DFN[i]) 61 Tarjan(i); 62 for(int i=1;i<=N;i++){ 63 find_degree(i); 64 } 65 if(scc==1) return; 66 for(int i=1;i<=scc;i++){ 67 if(in[i]==0) a++; 68 if(out[i]==0) b++; 69 } 70 } 71 void init(){ 72 tot = 0; 73 a=0,b=0; 74 memset(head,-1,sizeof(head)); 75 memset(in,0,sizeof(in)); 76 memset(out,0,sizeof(out)); 77 } 78 int main(){ 79 int n,m,u,v,T; 80 cin>>T; 81 while(T--){ 82 scanf("%d%d",&n,&m); 83 init(); 84 for(int i=1;i<=m;i++){ 85 scanf("%d%d",&u,&v); 86 addedge(u,v); 87 } 88 solve(n); 89 cout<<max(a,b)<<endl; 90 } 91 return 0; 92 }
时间: 2024-10-11 22:05:43