zoukankan      html  css  js  c++  java
  • hdu3836联通的强还原性点

    Equivalent Sets

    Time Limit: 12000/4000 MS (Java/Others)    Memory Limit: 104857/104857 K (Java/Others)
    Total Submission(s): 2526    Accepted Submission(s): 857


    Problem Description
    To prove two sets A and B are equivalent, we can first prove A is a subset of B, and then prove B is a subset of A, so finally we got that these two sets are equivalent.
    You are to prove N sets are equivalent, using the method above: in each step you can prove a set X is a subset of another set Y, and there are also some sets that are already proven to be subsets of some other sets.
    Now you want to know the minimum steps needed to get the problem proved.
     

    Input
    The input file contains multiple test cases, in each case, the first line contains two integers N <= 20000 and M <= 50000.
    Next M lines, each line contains two integers X, Y, means set X in a subset of set Y.
     

    Output
    For each case, output a single integer: the minimum steps needed.
     

    Sample Input
    4 0 3 2 1 2 1 3
     

    Sample Output
    4 2

    #include <iostream>
    #include <cstdio>
    #include <cstdlib>
    #include <cstring>
    #include <string>
    #include <queue>
    #include <algorithm>
    #include <map>
    #include <cmath>
    #include <iomanip>
    #define INF 99999999
    typedef long long LL;
    using namespace std;
    
    const int MAX=20000+10;
    int n,m,size,top,index,ind,oud;
    int head[MAX],dfn[MAX],low[MAX],stack[MAX];
    int mark[MAX],flag[MAX];
    //dfn表示点u出现的时间,low表示点u能到达所属环中最早出现的点(记录的是到达的时间) 
    
    struct Edge{
    	int v,next;
    	Edge(){}
    	Edge(int V,int NEXT):v(V),next(NEXT){}
    }edge[50000+10];
    
    void Init(int num){
    	for(int i=0;i<=num;++i)head[i]=-1;
    	size=top=index=ind=oud=0;
    }
    
    void InsertEdge(int u,int v){
    	edge[size]=Edge(v,head[u]);
    	head[u]=size++;
    }
    
    void tarjan(int u){
    	if(mark[u])return;
    	dfn[u]=low[u]=++index;
    	stack[++top]=u;
    	mark[u]=1;
    	for(int i=head[u];i != -1;i=edge[i].next){
    		int v=edge[i].v;
    		tarjan(v);
    		if(mark[v] == 1)low[u]=min(low[u],low[v]);//必须点v在栈里面才行 
    	}
    	if(dfn[u] == low[u]){
    		++ind,++oud;//记录缩点之后的点的个数,方便计算入度和出度为0的点的个数
    		while(stack[top] != u){
    			mark[stack[top]]=-1;
    			low[stack[top--]]=low[u];
    		}
    		mark[u]=-1;
    		--top;
    	}
    }
    
    int main(){
    	int u,v;
    	while(~scanf("%d%d",&n,&m)){
    		Init(n);
    		for(int i=0;i<m;++i){
    			scanf("%d%d",&u,&v);
    			InsertEdge(u,v);
    		}
    		memset(mark,0,sizeof mark);
    		for(int i=1;i<=n;++i){
    			if(mark[i])continue;
    			tarjan(i);
    		}
    		if(ind == 1){printf("0
    ");continue;}//仅仅剩一个点了表示原图数个强联通图 
    		for(int i=0;i<=n;++i)mark[i]=flag[i]=0;
    		for(int i=1;i<=n;++i){
    			for(int j=head[i];j != -1;j=edge[j].next){
    				v=edge[j].v;
    				if(low[i] == low[v])continue;
    				if(mark[low[i]] == 0)--oud;//mark标记点i是否已有出度 
    				if(flag[low[v]] == 0)--ind;//flag标记点v是否已有入度
    				mark[low[i]]=flag[low[v]]=1;
    			}
    		}
    		printf("%d
    ",max(ind,oud));
    	} 
    	return 0;
    }


    版权声明:本文博主原创文章,博客,未经同意不得转载。

  • 相关阅读:
    解题:HNOI 2008 玩具装箱
    2016级算法第一次上机助教版解题报告
    求解斐波那契数列复杂度分析
    数据库复习之规范化理论应用(第八次上机内容)
    数据库复习之规范化理论
    题目1042:Coincidence(最长公共子序列)
    题目1020:最小长方形(简单)
    题目1016:火星A+B(字符串拆分)
    题目1014:排名(结构体排序)
    题目1021:统计字符(hash简单应用)
  • 原文地址:https://www.cnblogs.com/zfyouxi/p/4828806.html
Copyright © 2011-2022 走看看