首页 > 代码库 > UVa LA 4287 强连通 (类似 hdu 3836)

UVa LA 4287 强连通 (类似 hdu 3836)

题目:https://icpcarchive.ecs.baylor.edu/index.php?option=com_onlinejudge&Itemid=8&page=show_problem&category=25&problem=2288&mosmsg=Submission+received+with+ID+1488188

本题可在大白书的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;}/*23 21 21 33 21 21 3  */