hdu 2767 Proving Equivalences (tarjan + 缩点)
来源:互联网 发布:java搭建项目的流程 编辑:程序博客网 时间:2024/05/19 01:32
/*题目大意:给定一张有向图,问最少添加几条边使得有向图成为一个强连通图。解题思路:缩点后找入度为0的点和出度为0的点,统计个数,选择大的那个数就是答案。 如果出度为0的个数n比入度为0的个数m多,那添加n条边,从当前出度为0的点到 其他入度为0的点,肯定能成为强连通图,同理可得m大也可以。(各连通分支间 可能需要1条或2条,才能使两个连通分支相互连通。)*/#include<iostream>#include<string.h>#define size 20010using namespace std;int dfn[size],low[size];int head[size] , stack[size] , in[size];int lian[size] ,rd[size] ,cd[size];struct E { int v , next;}e[50050];int n,m,sum , top ,step , s;void init(){ for(int i=0;i<size;i++) { dfn[i]=low[i]=stack[i]=in[i]=lian[i]=0; head[i]=-1; } top=0; sum=step=0; s=-1;}void insert(int u , int v){ e[top].v=v; e[top].next=head[u]; head[u]=top++;}void tarjan(int u){ int v; dfn[u]=low[u]=++step; in[u]=1; stack[++s]=u; for(int i=head[u];i!=-1;i=e[i].next) { v=e[i].v; if(!dfn[v]) { tarjan(v); if(low[v]<low[u]) low[u]=low[v]; } else if(in[v] && dfn[v]<low[u]) low[u]=dfn[v]; } if(dfn[u]==low[u]) { sum++; do { v=stack[s--]; in[v]=0; lian[v]=sum; }while(u!=v); }}int main(){ int t; int a, b; scanf("%d",&t); int rds,cds; while(t--) { init(); rds=cds=0; scanf("%d%d",&n,&m); for(int i=0;i<m;i++) { scanf("%d%d",&a,&b); insert(a, b); } for(int i=1;i<=n;i++) if(!dfn[i]) tarjan(i); if(sum==1) printf("0\n"); else { for(int i=0;i<=sum;i++) rd[i]=cd[i]=0; for(int i=1;i<=n;i++) { for(int j=head[i];j!=-1; j=e[j].next) { int v=e[j].v; if(lian[i]!=lian[v]) { cd[lian[i]]++; rd[lian[v]]++; } } } for(int i=1;i<=sum;i++) { if(cd[i]==0) cds++; if(rd[i]==0) rds++; } if(cds>rds) printf("%d\n",cds); else printf("%d\n",rds); } } return 0;}