题意:给你一个有向图,然后添边,让该图成为连通分量为1的连通图,需要添加的边数
思路:强连通+缩点,记录每个连通分量的入度和初度为0 的个数。找一个最大的值
刚开始自己认为如果一个连通分量的入度为1,那么它的出度一定为0,这是极大的错误。
#include<iostream>
#include<algorithm>
#include<cstdio>
#include<string.h>
#include<vector>
#include<stack>
#define maxn 10010
using namespace std;
stack<int>S;
vector<int>gra[2*maxn];
int T,n,m;
int dfn[2*maxn],low[2*maxn],vis[2*maxn],belong[2*maxn],ind[2*maxn],outd[2*maxn];
int sum;
int tem;
int MIN(int a,int b)
{
return a>b?b:a;
}
void tarjan(int pox)
{
vis[pox]=2;
dfn[pox]=low[pox]=++sum;
S.push(pox);
for(int i=0; i<gra[pox].size(); i++)
{
int t=gra[pox][i];
if(!dfn[t])
{
tarjan(t);
low[pox]=MIN(low[pox],low[t]);
}
else if(vis[t]==2)
{
low[pox]=MIN(low[pox],dfn[t]);
}
}
if(low[pox]==dfn[pox])
{
tem++;
while(!S.empty())
{
int gh=S.top();
S.pop();
belong[gh]=tem;
ind[gh]=0;
outd[gh]=0;
vis[gh]=1;
if(gh==pox)
break;
}
}
}
int main()
{
int a,b;
int inMax,outMax;
while(scanf("%d",&T)!=EOF)
{
while(T--)
{
tem=sum=0;
inMax=outMax=0;
scanf("%d%d",&n,&m);
memset(dfn,0,sizeof(dfn));
memset(vis,0,sizeof(vis));
memset(low,0,sizeof(low));
for(int i=0; i<2*maxn; i++)
gra[i].clear();
while(!S.empty())
S.pop();
for(int i=0; i<m; i++)
{
scanf("%d%d",&a,&b);
gra[a].push_back(b);
}
for(int i=1; i<=n; i++)
if(!dfn[i])
tarjan(i);
if(tem==1)
{
printf("0\n");
continue;
}
for(int j=1; j<=n; j++)
for(int i=0; i<gra[j].size(); i++) //记录每个节点的入度:
{
if(belong[j]!=belong[gra[j][i]])
{
outd[belong[j]]++;
ind[belong[gra[j][i]]]++;
}
}
// printf("tem=%d\n",tem);
for(int i=1; i<=tem; i++)
{
if(!ind[i])
inMax++;
if(!outd[i])
outMax++;
}
/*
if(ind[i]==1)
inMax++;
else
outMax++;
*/
printf("%d\n",inMax>outMax?inMax:outMax);
}
}
return 0;
}