题目链接
题意:给n个点和m条有向边,问最少再加几条边使其变成强连通图。
先tarjan跑一遍,如果是强连通图就输出0。否则输出max(入度为0的点个数,出度为0的点个数)。
#include <iostream> #include<cstdio> #include<cstring> #include<cmath> #define N 22000 #define M 55000 using namespace std; struct node { int to,next; }e[M]; int dfn[N],low[N],head[N],in[N],out[N],cnt,scnt,top,q[N],v[N],belong[N],n,m; void init() { memset(head,-1,sizeof(head)); memset(dfn,0,sizeof(dfn)); memset(low,0,sizeof(low)); memset(in,0,sizeof(in)); memset(out,0,sizeof(out)); memset(belong,0,sizeof(belong)); 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 u) { int t; low[u]=dfn[u]=cnt++; q[top++]=u; v[u]=1; for(int i=head[u];i+1;i=e[i].next) { int c=e[i].to; if(!dfn[c]) { tarjan(c); low[u]=min(low[u],low[c]); } else if(v[c]) low[u]=min(low[u],dfn[c]); } if(low[u]==dfn[u]) { scnt++; do { t=q[--top]; v[t]=0; belong[t]=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 t=e[j].to; if(belong[i]!=belong[t]) { in[belong[t]]++; 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() { int T; cin>>T; while(T--) { cin>>n>>m; init(); for(int i=0;i<m;i++) { int u,v; scanf("%d%d",&u,&v); add_edge(u,v); } solve(); } }