题目:
我是超链接
题意:给一个有向图,要求加最少的边至强联通
题解:
先缩点,然后求入度为0和出度为0的max,就是出度为0的要向入度为0的连边,其余的要多连
一个缩点图中所有的点都有入度和出度的时候,这个图就是强连通分量了
代码:
#include <cstdio> #include <iostream> #include <cstring> #define M 50005 #define N 50005 using namespace std; int nxt[M*2],point[M*2],v[M*2],tot,tmp,n,m,NN,num; int dfn[N],low[N],strack[N],x[N],y[N],out[N],belong[N],in[N]; bool vis[N]; void cl() { tot=0;num=0;tmp=0;NN=0; memset(nxt,0,sizeof(nxt)); memset(point,0,sizeof(point)); memset(v,0,sizeof(v)); memset(dfn,0,sizeof(dfn)); memset(low,0,sizeof(low)); memset(strack,0,sizeof(strack)); memset(vis,0,sizeof(vis)); memset(in,0,sizeof(in)); memset(out,0,sizeof(out)); memset(belong,0,sizeof(belong)); } void addline(int x,int y) { ++tot; nxt[tot]=point[x]; point[x]=tot; v[tot]=y; } void tarjan(int now) { dfn[now]=low[now]=++NN; vis[now]=1; strack[++tmp]=now; for (int i=point[now];i;i=nxt[i]) if (!dfn[v[i]]) { tarjan(v[i]); low[now]=min(low[now],low[v[i]]); } else if (vis[v[i]]) low[now]=min(low[now],dfn[v[i]]); if (dfn[now]==low[now]) { num++; while (strack[tmp]!=now) { belong[strack[tmp]]=num; vis[strack[tmp]]=0; tmp--; } belong[strack[tmp]]=num; vis[strack[tmp]]=0; tmp--; } } int main() { int T,i; scanf("%d",&T); while (T--) { scanf("%d%d",&n,&m); cl(); int ans1=0,ans2=0; for (i=1;i<=m;i++) { scanf("%d%d",&x[i],&y[i]); addline(x[i],y[i]); } for (i=1;i<=n;i++) if (!dfn[i]) tarjan(i); for (i=1;i<=m;i++) if (belong[x[i]]!=belong[y[i]]) ++in[belong[y[i]]],++out[belong[x[i]]]; for (i=1;i<=num;i++) { if (!in[i]) ans1++; if (!out[i]) ans2++; } if (num==1) printf("0\n"); else printf("%d\n",max(ans1,ans2)); } }