//求有向图强连通分量个数和各节点属于哪个分量
//此题是求最少添加几条有向边使整个图成为强连通图
#include <iostream>
#include <vector>
#include <stack>
#include <cstring>
using namespace std;
const int maxn=20005;
vector<int> g[maxn];
stack<int> st;
int ord[maxn],low[maxn],id[maxn]; //id[i]记录第i个节点属于哪个连通分量
int cnt,scnt; //cnt记录访问次序,scnt是强连通分量个数
int n,m;
int indegree[maxn];
int outdegree[maxn];
void Tarjan(int e)
{
int t;
int min=low[e]=ord[e]=cnt++;
st.push(e);
for(int i=0;i<g[e].size();++i)
{
t=g[e][i];
if(ord[t]==-1) Tarjan(t);
if(low[t]<min) min=low[t];
}
if(min<low[e]) {low[e]=min; return;}
do{
id[t=st.top()]=scnt;
low[t]=n+1;
st.pop();
}while(t!=e);
++scnt;
}
void Search()
{
memset(ord,-1,sizeof(ord));
cnt=0; scnt=0;
for(int i=0;i<n;++i)
if(ord[i]==-1) Tarjan(i);
}
void base_vertex()
{
Search();
int t;
memset(indegree,0,sizeof(indegree));
memset(outdegree,0,sizeof(outdegree));
for(int i=0;i<n;++i)
{
for(int j=0;j<g[i].size();++j)
{
t=g[i][j];
if(id[t]!=id[i])
{
++indegree[id[t]];
++outdegree[id[i]];
}
}
}
}
int main()
{
int t; cin>>t;//t是样例组数
int in,out;
int u,v;
while(t--)
{
cin>>n>>m;//n为顶点数,m为有向边数
for(int i=0;i<n;++i)
g[i].clear();
for(int i=0;i<m;++i)
{
cin>>u>>v;
g[u-1].push_back(v-1);//下标从0到n-1
}
base_vertex();
in=0;out=0;
if(scnt==1) {cout<<0<<endl; continue;}
for(int i=0;i<scnt;++i)
{
if(indegree[i]==0) ++in;
if(outdegree[i]==0) ++out;
}
cout<<(in>out?in:out)<<endl;
}
return 0;
}
//求有向图强连通分量个数和各节点属于哪个分量
//此题是求最少添加几条有向边使整个图成为强连通图
#include <iostream>
#include <vector>
#include <stack>
#include <cstring>
using namespace std;
const int maxn=20005;
vector<int> g[maxn];
stack<int> st;
int ord[maxn],low[maxn],id[maxn]; //id[i]记录第i个节点属于哪个连通分量
int cnt,scnt; //cnt记录访问次序,scnt是强连通分量个数
int n,m;
int indegree[maxn];
int outdegree[maxn];
void Tarjan(int e)
{
int t;
int min=low[e]=ord[e]=cnt++;
st.push(e);
for(int i=0;i<g[e].size();++i)
{
t=g[e][i];
if(ord[t]==-1) Tarjan(t);
if(low[t]<min) min=low[t];
}
if(min<low[e]) {low[e]=min; return;}
do{
id[t=st.top()]=scnt;
low[t]=n+1;
st.pop();
}while(t!=e);
++scnt;
}
void Search()
{
memset(ord,-1,sizeof(ord));
cnt=0; scnt=0;
for(int i=0;i<n;++i)
if(ord[i]==-1) Tarjan(i);
}
void base_vertex()
{
Search();
int t;
memset(indegree,0,sizeof(indegree));
memset(outdegree,0,sizeof(outdegree));
for(int i=0;i<n;++i)
{
for(int j=0;j<g[i].size();++j)
{
t=g[i][j];
if(id[t]!=id[i])
{
++indegree[id[t]];
++outdegree[id[i]];
}
}
}
}
int main()
{
int t; cin>>t;//t是样例组数
int in,out;
int u,v;
while(t--)
{
cin>>n>>m;//n为顶点数,m为有向边数
for(int i=0;i<n;++i)
g[i].clear();
for(int i=0;i<m;++i)
{
cin>>u>>v;
g[u-1].push_back(v-1);//下标从0到n-1
}
base_vertex();
in=0;out=0;
if(scnt==1) {cout<<0<<endl; continue;}
for(int i=0;i<scnt;++i)
{
if(indegree[i]==0) ++in;
if(outdegree[i]==0) ++out;
}
cout<<(in>out?in:out)<<endl;
}
return 0;
}