• UVa11324 最大团


    题意:一个有向图中,求一个节点数最多的结点集,使得该结点任意两点u和v, 要么u可达v,要么v可达u,u和v互相可达也可以。

    思路:这一看就知道是最大团的定义了,可以说是最大团的模板题,可以先强连通缩点,缩点后就成了DAG(有向无环图),强连通里的点都可以满足要求,再求DAG的最长路径极为结果,每个强连通缩点后的点权即为该强连通的结点个数,而DAG求路径可用动态规划求。

    一开始我记录每个连通图结点个数时,在tarjan算法里面写,可是WA,后来放在缩点的地方就对了。这个真心不知道为什么了。

    #include<stdio.h>
    #include<string.h>
    
    const int maxn = 3000;
    const int maxm = 50009;
    struct node
    {
    	int v,next;
    }eg[maxm],tree[maxm];
    int head[maxn],root[maxn];
    int dfn[maxn],low[maxn],sta[maxn],insta[maxn],sum[maxn],belong[maxn];
    int tot,color,Index,top,n;
    int dp[maxn];
    
    inline int max(int a,int b){return a > b ? a : b;}
    inline int min(int a,int b){return a < b ? a : b;}
    
    void add(int a,int b)
    {
    	eg[tot].v = b;
    	eg[tot].next = head[a];
    	head[a] = tot++;
    }
    void addt(int a,int b)
    {
    	tree[tot].v = b;
    	tree[tot].next = root[a];
    	root[a] = tot++;
    }
    //求强连通
    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]);
    		}if(insta[v])
    		{
    			low[u] = min(low[u],dfn[v]);
    		}
    	}
    	if(low[u] == dfn[u])
    	{
    		color++;
    		int v;
    		do
    		{
    			v= sta[--top];
    			insta[v] = 0;
    			belong[v] = color;
    		//	sum[color] ++;  //为什么不可以在这里加
    		}while(u != v);
    	}
    }
     //缩点
    void Buildtree()
    {
    	tot = 0;
    	for(int u = 1;u <= n;u++)
    	{
    		sum[belong[u]] ++;	//每个连通图的结点个数
    		for(int i=head[u];i+1;i=eg[i].next)
    		{
    			int v= eg[i].v;
    			if(belong[u] != belong[v])
    			{
    				addt(belong[u],belong[v]);
    			}
    		}
    	}
    }
    
    void init()
    {
    	memset(dp,0,sizeof(dp));
    	memset(dfn,0,sizeof(dfn));
    	memset(low,0,sizeof(low));
    	memset(head,-1,sizeof(head));
    	memset(root,-1,sizeof(root));
    	memset(insta,0,sizeof(insta));
    	memset(belong,0,sizeof(belong));
    	memset(sum,0,sizeof(sum));
    	tot = Index = top = color = 0;
    }
    
    int Clique(int u)  	//dp求DAG的最长路径
    {  
        if(dp[u]>0) return dp[u];  
    	dp[u]=sum[u];  
        for(int i=root[u];i+1;i=tree[i].next)  
        {  
            int v=tree[i].v;  
            dp[u]=max(dp[u],Clique(v)+sum[u]);  
        }  
        return dp[u];  
    }  
      
    
    void work()
    {
    	int u,i,ans =0;
    	tot = 0;
    	for( u =1;u<=n;u++)
    	{
    		if(!dfn[u]) tarjan(u);
    	}
    	Buildtree();
    	for(i=1;i<=color;i++)
    	{
    		ans = max(ans,Clique(i));
    	}
    	printf("%d
    ",ans);
    }
    int main()
    {
    	int m,i,a,b,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
    5 5
    1 2
    2 3
    3 1
    4 1
    5 2
    5 5
    1 2
    2 3
    3 1
    4 1
    5 2
    
    */
    
  • 相关阅读:
    写日志
    读写excel
    python安装模块
    数据库
    日志和关键字查找
    时间戳
    os 模块
    图-最小生成树算法之Kruskal及其Java实现
    图-图的表示、搜索算法及其Java实现
    前端实现list排序
  • 原文地址:https://www.cnblogs.com/BruceNoOne/p/3864031.html
Copyright © 2020-2023  润新知