思路:首先同属一个州就证明两个城市是强连通的,又要使得对于每一个州里的任何两个城市u、v,都有不经过其他州的路从u到v或从v到u,其实就是一个二分图
#include<bits/stdc++.h>
using namespace std;
const int maxn = 5000+50;
int in0[maxn],out0[maxn];
vector<int>e[maxn];
int pre[maxn],lowlink[maxn],sccno[maxn],dfs_clock,scc_cnt;
stack<int>s;
struct Max_Match
{
int n;
vector<int>g[maxn];
bool vis[maxn];
int left[maxn];
void init(int n)
{
this->n=n;
for(int i = 0;i<=n;i++)
g[i].clear();
memset(left,-1,sizeof(left));
}
bool match(int u)
{
for(int i = 0;i<g[u].size();i++)
{
int v = g[u][i];
if(!vis[v])
{
vis[v]=1;
if(left[v]==-1 || match(left[v]))
{
left[v]=u;
return 1;
}
}
}
return false;
}
int solve()
{
int ans = 0;
for(int i = 1;i<=n;i++)
{
memset(vis,0,sizeof(vis));
if(match(i))ans++;
}
return ans;
}
}M;
void dfs(int u)
{
pre[u]=lowlink[u]=++dfs_clock;
s.push(u);
for(int i = 0;i<e[u].size();i++)
{
int v = e[u][i];
if(!pre[v])
{
dfs(v);
lowlink[u]=min(lowlink[u],lowlink[v]);
}
else if (!sccno[v])
lowlink[u]=min(lowlink[u],pre[v]);
}
if(lowlink[u]==pre[u])
{
scc_cnt++;
for(;;)
{
int x = s.top();
s.pop();
sccno[x]=scc_cnt;
if(x==u)break;
}
}
}
void find_scc(int n)
{
dfs_clock = scc_cnt = 0;
memset(sccno,0,sizeof(sccno));
memset(pre,0,sizeof(pre));
for(int i = 1;i<=n;i++)
if(!pre[i])
dfs(i);
}
int main()
{
int n,m,T;
scanf("%d",&T);
while(T--)
{
scanf("%d%d",&n,&m);
for(int i = 0;i<=n;i++)
e[i].clear();
for(int i = 0;i<m;i++)
{
int u,v;
scanf("%d%d",&u,&v);
e[u].push_back(v);
//M.g[u].push_back(v);
}
find_scc(n);
M.init(n);
for(int u = 1;u<=n;u++)
for(int i = 0;i<e[u].size();i++)
{
int v = e[u][i];
if(sccno[u]!=sccno[v])
M.g[sccno[u]].push_back(sccno[v]);
}
printf("%d\n",scc_cnt-M.solve());
}
}