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.
InputThe input file contains multiple test cases, in each case, the first line contains two integers N <= 20000 and M <= 50000.
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.
Next M lines, each line contains two integers X, Y, means set X in a subset of set Y.OutputFor each case, output a single integer: the minimum steps needed.Sample Input
4 0 3 2 1 2 1 3Sample 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.
#include <cstdio>
#include <algorithm>
#include <cstring>
#include <vector>
#include <stack>
#define MAX 200010
using namespace std;
vector<int> MGraph[MAX];
int DFN[MAX];
int LOW[MAX];
int inStack[MAX];
stack<int> s;
int scc_cnt = 0;
int tot = 1;
int n, m;
int sccno[MAX];
int outDegree[MAX];
int inDegree[MAX];
void init() {
for( int i = 0; i < MAX; i++ ) MGraph[i].clear();
while( !s.empty() ) s.pop();
memset( DFN, 0, sizeof( DFN ) );
memset( LOW, 0, sizeof( LOW ) );
memset( inStack, 0, sizeof( inStack ) );
memset( inDegree, 0, sizeof( inDegree ) );
memset( outDegree, 0, sizeof( outDegree ) );
memset( sccno, 0, sizeof( sccno ) );
scc_cnt = 0;
tot = 1;
}
void tarjan( int u ) {
inStack[u] = 1;
DFN[u] = LOW[u] = tot++;
s.push( u );
for( int i = 0; i < MGraph[u].size(); i++ ) {
int v = MGraph[u][i];
if( !DFN[v] ) {
tarjan( v );
LOW[u] = min( LOW[u], LOW[v] );
}
else if( inStack[v] ) {
LOW[u] = min( LOW[u], DFN[v] );
}
}
if( LOW[u] == DFN[u] ) {
scc_cnt++;
int cur;
do {
cur = s.top();
sccno[cur] = scc_cnt;
inStack[cur] = 0;
s.pop();
} while( cur != u );
}
}
void solve() {
for( int i = 1; i <= n; i++ ) {
if( !DFN[i] ) tarjan( i );
}
}
int main() {
while( scanf( "%d%d", &n, &m ) != EOF ) {
init();
for( int i = 0; i < m; i++ ) {
int a, b;
scanf( "%d%d", &a, &b );
MGraph[a].push_back( b );
}
solve();
for( int i = 1; i <= n; i++ ) {
for( int j = 0; j < MGraph[i].size(); j++ ) {
int v = MGraph[i][j];
int x = sccno[i];
int y = sccno[v];
if( x != y ) {
inDegree[x]++;
outDegree[y]++;
}
}
}
int a = 0, b = 0;
for( int i = 1; i <= scc_cnt; i++ ) {
if( !inDegree[i] ) a++;
if( !outDegree[i] ) b++;
}
printf( "%d\n", scc_cnt == 1 ? 0 : max( a, b ) );
}
return 0;
}