题目连接:http://acm.hdu.edu.cn/showproblem.php?pid=3861
/*题解:
state划分规则:至少存在一条路径可以从city u到city v,
也存在一条路径可以从city v到city u,则u,v必须分在一个state
(强连通子图必须分在一个state).一个state内u,v至少一方能够到达对方,
一个点只能分在一个state.(最小路径覆盖).将每个强连通图看成一个点,二分匹配。
*/
#include <cstdio>
#include <cstring>
#include <vector>
#define MAXN 5002
#define INF 0x3f3f3f3f
using namespace std;
struct node
{
int to,next;
}edge[100002];
vector<int> mp[MAXN];
int n,m,belong[MAXN],from[MAXN],visited[MAXN];
int head[MAXN],instack[MAXN],low[MAXN],dfn[MAXN];
int stack[MAXN],tot,Dindex,top,Bcnt;
void Init()
{//初始化
tot=0,top=0,Dindex=0,Bcnt=0;
memset(head,-1,sizeof(head));
memset(instack,0,sizeof(instack));
memset(dfn,0,sizeof(dfn));
memset(low,0,sizeof(low));
memset(belong,0,sizeof(belong));
for(int i=0;i<=n;++i)
mp[i].clear();
}
void addEdge(int from,int to)
{
edge[tot].to=to;
edge[tot].next=head[from];
head[from]=tot++;
}
void Tarjan(int x)
{
int i,u;
dfn[x]=low[x]=++Dindex;//时间戳
stack[top++]=x;
instack[x]=1;
for(i=head[x];i!=-1;i=edge[i].next)
{
u=edge[i].to;
if(!dfn[u])
{
Tarjan(u);
low[x]=low[x]>low[u]?low[u]:low[x];
}
else if(instack[u]&&low[x]>dfn[u])
low[x]=dfn[u];
}
if(low[x]==dfn[x])
{
int v;
Bcnt++;
do
{
v=stack[--top];
instack[v]=0;
belong[v]=Bcnt;
} while (v!=x);
}
}
int find(int x)//匈牙利算法
{
int i,temp,size;
size=mp[x].size();
for(i=0;i<size;++i)
{
temp=mp[x][i];
if(!visited[temp])
{
visited[temp]=1;
if(from[temp]==-1||find(from[temp]))
{
from[temp]=x;
return 1;
}
}
}
return 0;
}
int hungary()
{
int i,sum=0;
memset(from,-1,sizeof(from));
for(i=1;i<=Bcnt;++i)
{
memset(visited,0,sizeof(visited));
if(find(i))
sum++;
}
return sum;
}
int Scan()
{
char ch;
int ret=0;
while((ch=getchar())<'0'||ch>'9');
while(ch>='0'&&ch<='9')
{
ret=ret*10+(ch-'0');
ch=getchar();
}
return ret;
}
int main()
{
int test,i,u,v,cnt;
scanf("%d",&test);
while(test--)
{
scanf("%d %d",&n,&m);
Init();
while(m--)
{
u=Scan();
v=Scan();
//scanf("%d %d",&u,&v);
addEdge(u,v);
}
for(i=1;i<=n;++i)
{
if(!dfn[i])
Tarjan(i);
}
for(u=1;u<=n;++u)
{
for(i=head[u];i!=-1;i=edge[i].next)
{
v=edge[i].to;
if(belong[u]!=belong[v])//u,v不在一个强连通图里.
mp[belong[u]].push_back(belong[v]);
}
}
cnt=hungary();
printf("%d\n",Bcnt-cnt);
}
return 0;
}