题意:给n个点和m条有向边,问最少再加几条边使其变成强连通图。和hdu2767同样的解法。
#include <iostream>
#include<cstdio>
#include<cmath>
#include<cstring>
#define N 22000
#define M 55000
using namespace std;
struct node
{
int next,to;
}e[M];
int head[N],cnt,scnt,top,n,m,dfn[N],low[N],v[N],belong[N],in[N],out[N],q[N];
void init()
{
memset(head,-1,sizeof(head));
memset(dfn,0,sizeof(dfn));
memset(low,0,sizeof(low));
memset(v,0,sizeof(v));
memset(belong,0,sizeof(belong));
memset(in,0,sizeof(in));
memset(out,0,sizeof(out));
cnt=scnt=top=0;
}
void add_edge(int u,int v)
{
e[cnt].to=v;
e[cnt].next=head[u];
head[u]=cnt++;
}
void tarjan(int t)
{
low[t]=dfn[t]=cnt++;
q[top++]=t;
v[t]=1;
for(int i=head[t];i+1;i=e[i].next)
{
int u=e[i].to;
if(!dfn[u])
{
tarjan(u);
low[t]=min(low[t],low[u]);
}
else if(v[u])
low[t]=min(low[t],dfn[u]);
}
int u;
if(low[t]==dfn[t])
{
scnt++;
do
{
u=q[--top];
v[u]=0;
belong[u]=scnt;
}while(t!=u);
}
}
void solve()
{
for(int i=1;i<=n;i++)
if(!dfn[i]) tarjan(i);
if(scnt==1)
{
cout<<0<<endl;
return;
}
for(int i=1;i<=n;i++)
for(int j=head[i];j+1;j=e[j].next)
{
int u=e[j].to;
if(belong[u]!=belong[i])
{
in[belong[u]]++;
out[belong[i]]++;
}
}
int a=0,b=0;
for(int i=1;i<=scnt;i++)
{
if(in[i]==0) a++;
if(out[i]==0) b++;
}
cout<<max(a,b)<<endl;
}
int main()
{
while(~scanf("%d%d",&n,&m))
{
init();
for(int i=0;i<m;i++)
{
int u,v;
scanf("%d%d",&u,&v);
add_edge(u,v);
}
solve();
}
}