• 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
    ");
    		else
    			printf("%d
    ",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
    
    
      */
    
  • 相关阅读:
    洛谷P1908《逆序对》
    洛谷P3884《[JLOI2009]二叉树问题》
    最近公共祖先 LCA
    洛谷P1531《I Hate It》
    洛谷P1563「NOIP2016」《玩具谜题》
    乘法逆元求法
    CF56E 【Domino Principle】
    CF638C 【Road Improvement】
    Luogu
    2018.8.7提高B组模拟考试
  • 原文地址:https://www.cnblogs.com/BruceNoOne/p/3854201.html
Copyright © 2020-2023  润新知