/*
唉~~英语不好理解不了题意。我是网上先看别人做的题意,在做题。 唉~~~~~~悲哀~~~
题意:有个国王 要给自己的国家分块,然后给你一些路,两个城市可以互相到达的城市要在一个块(强连通分量),然后每个
城市只能在一个快,然后一个强连通到另一个强联通分量有变得可以划分为一个块,问你最少花费的块数,理解好题意就好做了。
思路:先用trajan算法缩点,然后重建图,重建图之后 就是一个最小路径覆盖了。
*/
#include<stdio.h>
#include<string.h>
#include<vector>
using namespace std;
int n,m;
vector<int>map[5001];
vector<int>map1[5001];
int dfn[5001],low[5001];//dfn表示点被访问的次序,low[i]表示i点能够追溯到本个强联通分量最前访问次序的那个点的访问次序。
int flag[5001];//标志素组
int stack[5001];//用来保存已经访问了得点
int color[5001];//染色
int match[5001];
int vis[5001];
int c;
int count=1,sign=0;
int min(int x,int y)
{
if(x>y) return y;
return x;
}
int tarjan(int u)
{ flag[u]=1;
dfn[u]=low[u]=count++;
stack[++c]=u;//赋初值
for(int i=0;i<map[u].size();i++)
{ int v=map[u][i];
if(!flag[v])
{
tarjan(v);
low[u]=min(low[u],low[v]);
}
else if(flag[v]==1)low[u]=min(low[u],low[v]);
}
if(dfn[u]==low[u])
{
sign++;
do
{ //printf("%d ",stack[c]);
color[stack[c]]=sign;
flag[stack[c]]=-1;
}
while(stack[c--]!=u&&c>=0);
}
}
void inint()
{
for(int i=1;i<=n;i++)
{
map[i].clear();
map1[i].clear();
}
}
int find(int x)
{
for(int i=0;i<map1[x].size();i++)
{
int v=map1[x][i];
if(!vis[v])
{
vis[v]=1;
if(match[v]==-1||find(match[v]))
{
match[v]=x;
return 1;
}
}
}
return 0;
}
int solve()
{
memset(match,-1,sizeof(match));
int ans=0;
for(int i=1;i<=sign;i++)
{
memset(vis,0,sizeof(vis));
if(find(i)) ans++;
}
return ans;
}
int main()
{
int t;
scanf("%d",&t);
while(t--)
{ scanf("%d%d",&n,&m);
inint();
for(int i=1;i<=m;i++)
{
int x,y;
scanf("%d%d",&x,&y);
map[x].push_back(y);
}
sign=0;c=0;
memset(low,0,sizeof(low));
memset(dfn,0,sizeof(dfn));
memset(flag,0,sizeof(flag));
memset(color,0,sizeof(color));
for(int i=1;i<=n;i++)
if(!flag[i])tarjan(i);
for(int i=1;i<=n;i++)
{
for(int j=0;j<map[i].size();j++)
{
if(color[i]!=color[map[i][j]])
{
map1[color[i]].push_back(color[map[i][j]]);
}
}
}
printf("%d\n",sign-solve());
}
}
hdu3861
最新推荐文章于 2018-07-29 16:25:00 发布