• 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;
    }


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

  • 相关阅读:
    [转载]HAO123的迷思——谈谈SEO
    [转]软件版本命名规范
    [转载]万能讲话稿
    世界各国(地区)货币名称及其进位制
    [转载]SDK相关概念
    MeteoInfoJava解析与绘图教程(六)
    MeteoInfoJava解析与绘图教程(七)_图层添加站点名称或区域名称
    测试工具备查
    背景样式
    38年一遇的双七夕,今天你怎样过情人节?
  • 原文地址:https://www.cnblogs.com/zfyouxi/p/4828806.html
Copyright © 2020-2023  润新知