UVa LA 4287 强连通 (类似 hdu 3836)
本题可在大白书的322页找到。
题意:给你一些有向边,问你至少需要加多少条边使之整个图强连通。
思路:先强连通缩点,缩点之后的图就不连通了,如果缩点后的点的入度为零,则没有出去的边,就必须加一条出去的边,才可以和其他点连通,同理,出度为零的也要加边,所以最后所需要加的最少的边为max(入度为零的点,出度为零的点)。
本题其实和hdu3836类似
代码:
#include<cstdio> #include<algorithm> #include<cstring> using namespace std; const int maxn = 20009; const int maxm = 50009; struct node { int v,next; }eg[maxm]; int head[maxn],in[maxn],out[maxn],belong[maxn]; int insta[maxn],dfn[maxn] ,low[maxn],sta[maxn]; int tot,Index,top,color,n; inline int min(int a,int b){return a < b ? a : b;} inline int max(int a,int b){return a > b ? a : b;} inline void add(int a,int b) { eg[tot].v = b; eg[tot].next = head[a]; head[a] = tot++; } void init() { memset(low,0,sizeof(low)); memset(dfn,0,sizeof(dfn)); memset(sta,0,sizeof(sta)); memset(head,-1,sizeof(head)); memset(belong,0,sizeof(belong)); memset(in,0,sizeof(in)); memset(out,0,sizeof(out)); tot = Index = top = color = 0; } void tarjan(int u) { dfn[u] = low[u] = ++Index; sta[top++] = u; insta[u] = 1; for(int i = head[u];i+1;i=eg[i].next) { int v= eg[i].v; if(!dfn[v]) { tarjan(v); low[u] = min(low[u],low[v]); }else if(insta[v]) { low[u] = min(low[u],dfn[v]); } } if(low[u] == dfn[u]) { int v; color ++; //强连通个数 do { v = sta[--top]; insta[v] = 0; belong[v] = color; }while(u != v); } } void buildtree() { for(int u=1;u<=n;u++) { for(int i = head[u];i+1;i=eg[i].next) { int v = eg[i].v; if(belong[u] != belong[v]) //缩点 { out[belong[u]] ++; in[belong[v]] ++; } } } } void work() { int i,a=0,b=0; for(i = 1;i<=n;i++) if(!dfn[i]) tarjan(i); buildtree(); for(i=1;i<=color;i++) { if(in[i] == 0) a++; //入度为零的点 if(out[i] == 0) b++; //出度为零的点 } if(color == 1) //图本身是强连通的就不需要 printf("0\n"); else printf("%d\n",max(a,b)); } int main() { int a,b,m,i; int t; scanf("%d",&t); while(t--) { init(); scanf("%d%d",&n,&m); for(i=0;i<m;i++) { scanf("%d%d",&a,&b); add(a,b); } work(); } return 0; } /* 2 3 2 1 2 1 3 3 2 1 2 1 3 */