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


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

  • 相关阅读:
    EOS 数据库RAM使用量的计算
    EOS require_auth函数
    EOS测试链智能合约部署调用
    安装EOS合约工具eosio.cdt
    Linux Ubuntu下搭建Flutter桌面环境
    VMware虚拟机与物理机共享文件的方法总结
    虚拟机macOS Mojave10.14安装XCode10.1
    VMware14 安装 macOS Mojave教程
    VMware 14安装OS X10.11
    Mac OS虚拟机安装VMware Tools的方法
  • 原文地址:https://www.cnblogs.com/zfyouxi/p/4828806.html
Copyright © 2011-2022 走看看