Problem Description
To prove two sets A and B are equivalent, we can first prove A is a subset of B, and then prove B is a subset of A, so finally we got that these two sets are equivalent. You are to prove N sets are equivalent, using the method above: in each step you can prove a set X is a subset of another set Y, and there are also some sets that are already proven to be subsets of some other sets. Now you want to know the minimum steps needed to get the problem proved.
Input
The input file contains multiple test cases, in each case, the first line contains two integers N <= 20000 and M <= 50000. Next M lines, each line contains two integers X, Y, means set X in a subset of set Y.
Output
For each case, output a single integer: the minimum steps needed.
Sample Input
4 0
3 2
1 2
1 3
Sample Output
4 2
Hint
Case 2: First prove set 2 is a subset of set 1 and then prove set 3 is a subset of set 1.Source
把tarjan复习了一遍
1 题目描述:将题目中的集合转换为顶点,A集合是B集合的子集,转换为一条有向边<A,B>,即题目给我们一个有向图,问最少需要添加多少条边使之成为强连通图。
2 解题思路:通过tarjan算法找出图中的所有强连通分支,并将每一个强连通分支缩成一个点(因为强连通分量本身已经满足两两互相可达)。
3 要使缩点后的图成为强连通图,每个顶点最少要有一个入度和一个出度,一条边又提供一个出度和一个入度。
4 所以可以通过统计没有入度的顶点数 noInDegree 和 没有出度的顶点数 noOutDegree。
5 所需要添加的边数就是noInDegree和noOutDegree中的最大值。
1 #include<iostream> 2 #include<cstdio> 3 #include<cstring> 4 #include<stack> 5 #include<vector> 6 using namespace std; 7 #define N 20006 8 #define inf 1<<26 9 int n,m; 10 struct Node 11 { 12 int from; 13 int to; 14 int next; 15 }edge[N<<6]; 16 int tot;//表示边数,边的编号 17 int head[N]; 18 int vis[N]; 19 int tt; 20 int scc; 21 stack<int>s; 22 int dfn[N],low[N]; 23 int col[N]; 24 25 void init()//初始化 26 { 27 tt=0; 28 tot=0; 29 memset(head,-1,sizeof(head)); 30 memset(dfn,-1,sizeof(dfn)); 31 memset(low,0,sizeof(low)); 32 memset(vis,0,sizeof(vis)); 33 memset(col,0,sizeof(col)); 34 } 35 36 void add(int s,int u)//邻接矩阵函数 37 { 38 edge[tot].from=s; 39 edge[tot].to=u; 40 edge[tot].next=head[s]; 41 head[s]=tot++; 42 } 43 44 void tarjan(int u)//tarjan算法找出图中的所有强连通分支 45 { 46 dfn[u] = low[u]= ++tt; 47 vis[u]=1; 48 s.push(u); 49 int cnt=0; 50 for(int i=head[u];i!=-1;i=edge[i].next) 51 { 52 int v=edge[i].to; 53 if(dfn[v]==-1) 54 { 55 // sum++; 56 tarjan(v); 57 low[u]=min(low[u],low[v]); 58 } 59 else if(vis[v]==1) 60 low[u]=min(low[u],dfn[v]); 61 } 62 if(dfn[u]==low[u]) 63 { 64 int x; 65 scc++; 66 do{ 67 x=s.top(); 68 s.pop(); 69 col[x]=scc; 70 vis[x]=0; 71 }while(x!=u); 72 } 73 } 74 75 int main() 76 { 77 while(scanf("%d%d",&n,&m)==2 && n+m) 78 { 79 80 init(); 81 82 scc=0;//scc表示强连通分量的个数 83 while(m--) 84 { 85 int a,b; 86 scanf("%d%d",&a,&b); 87 add(a,b);//构造邻接矩阵 88 } 89 for(int i=1;i<=n;i++) 90 { 91 if(dfn[i]==-1) 92 { 93 tarjan(i); 94 } 95 } 96 //printf("%d ",scc); 97 98 99 int inde[N]; 100 int outde[N]; 101 memset(inde,0,sizeof(inde)); 102 memset(outde,0,sizeof(outde)); 103 for(int i=0;i<tot;i++) 104 { 105 int a=edge[i].from; 106 int b=edge[i].to; 107 if(col[a]!=col[b]) 108 { 109 inde[col[b]]++; 110 outde[col[a]]++; 111 } 112 } 113 114 int ans1=0; 115 int ans2=0; 116 for(int i=1;i<=scc;i++) 117 { 118 if(inde[i]==0) 119 { 120 ans1++; 121 } 122 if(outde[i]==0) 123 { 124 ans2++; 125 } 126 } 127 if(scc==1) 128 { 129 printf("0 "); 130 continue; 131 } 132 printf("%d ",max(ans1,ans2)); 133 134 } 135 return 0; 136 }