#include <iostream>#include <cstdio>#include <queue>#include <cstring>#include <string>#include <cmath>#include <vector>#include <map>#include <stack>#include <algorithm>//#include "myAlgorithm.h"#define MAX 100005#define OFFENCE (1e9 + 5)#define INF (1e8 + 5)#define eps 1e-9#define Rep(s, e) for( int i = s; i <= e; i++)#define Cep(e, s) for( int j = e; j >= s; j --)#define PI acos(-1.0)//#pragma comment(linker, "/STACK:36777216") ///传说中的外挂using namespace std;/** 可以抽象为求:强连通分量之间至少增加多少跳边,使得分量减少为1 先强连通(缩点), 变成n‘个孤立的集合, 集合是有向树, ////////// ------------------------------------------------------------------ “ 树的分支数和就是答案?” --->直觉一般都是错误的 没办法了, 在DIY里求助了一下, 好受打击, 都是神牛~~~, 回答之后问了下:"这不是,b题么,poj某陈题吧, 啊啊啊啊奔~溃,桑心" 根据回答:俄前面想的是对的, 先缩点, 然后变成上诉所有的集合, 其实是一个dag(Directed Acyclic Graph无环路有向图), 然后0初度和0入度的点数的最大值就是答案; 为神马呢, 当一个图中不存在出度或者入度为0的点, 那么这个图能强连通~, 这个很显然, 在一个强连通图中增加一个点, 只要给一个出度和入度, 新的图也是强连通图, 因为显然任意两两想通 相反, 如果一个点加入强连通图中, 只有出度或者入度, 那么必然不能两两想通, 得证~! 特殊情况:dag中只有一个节点的话, 显然答案是0; G++Wa, C++Ac 为嘛我也不懂~*/int n, m;int dfn[MAX], low[MAX], v[MAX];int index, num;vector<vector<int> >adj;stack<int>s;int nodeSet[MAX];int in[MAX], out[MAX];void tarjan(int node){ s.push(node); v[node] = 1; dfn[node] = low[node] = ++index; int len = adj[node].size(), pos; Rep(0, len - 1){ pos = adj[node][i]; if(!dfn[pos]){ tarjan(pos); low[node] = min(low[node], low[pos]); }else if(v[pos]){ low[node] = min(low[node], dfn[pos]); } } if(dfn[node] == low[node]){ num++; while(!s.empty()){ int t = s.top(); s.pop(); //cout<<t<<" "; v[t] = 0; nodeSet[t] = num; if(t == node)break; }///cout<<endl; }}void init(){ memset(v, 0, sizeof(v)); memset(dfn, 0, sizeof(dfn)); memset(low, 0, sizeof(low)); memset(nodeSet, 0, sizeof(nodeSet)); memset(in, 0, sizeof(in)); memset(out, 0, sizeof(out)); num = index = 0; while(!s.empty()){ s.pop(); } adj.assign(n+ 2, vector<int>() );}int main(){ int T; cin>>T; while(T--){ cin>>n>>m; init(); int a, b; Rep(0, m - 1){ cin>>a>>b; adj[a].push_back(b); } Rep(1, n){ if(!dfn[i]){ tarjan(i); } } if(num < 2){cout<<0<<endl; continue;}// cout<<"num"<<num<<endl;// Rep(1, num){// for(int j = 1; j <= n ;j++){// if(nodeSet[j] == i){// cout<<j<<" ";// }// }cout<<endl;// } int ins = 0, outs = 0; Rep(1, n){ int len = adj[i].size(), pos; for(int j = 0; j < len ;j++){ pos = adj[i][j]; if(nodeSet[i] != nodeSet[pos]){ in[nodeSet[pos]]++; out[nodeSet[i]]++; } } } Rep(1, num){ if(!in[i])ins++; if(!out[i])outs++; } cout<<max(ins, outs)<<endl; } return 0;}/***/