zoukankan      html  css  js  c++  java
  • ZOJ 3630 Information 强连通

    题意:n m表示n个节点,m条边,下面m行a b 表示a-b点有一条有向边

    题目:给定有向图,删去一个点后,可以求出该图中强连通分量中最大的点数

    问:删去某点后,最大点数 最小是多少

    思路:枚举删点,强连通求最大分量 

    mark

    #include<stdio.h>
    #include<iostream>
    #include<math.h>
    #include<queue>
    #include<vector>
    #include<string.h>
    #include<algorithm>
    #include<stack>
    
    #define N 1000
    #define INF64 1152921504606846976
    #define INF32 2147483647
    #define R(x) x<<1|1
    #define L(x) x<<1
    #define Mid(x,y) (x+y)>>1
    #define ll int
    using namespace std;
    vector<int>G[N],Tarjan[N];//Tarjan存下所有的强连通,其大小用 tar记录
    stack<int>mystack;
    int n,m,tar;
    
    inline ll Max(ll a,ll b){return a>b?a:b;}
    inline ll Min(ll a,ll b){return a<b?a:b;}
    
    int DFN[N],Low[N],Time,del;//del表示当前删除的点  小写的time会redeclared
    bool instack[N],vis[N];
    void tarjan(int u){
    	int v;
    	DFN[u]=Low[u]=++Time;
    	mystack.push(u);  instack[u]=true;
    	vis[u]=true;
    	for(int i=0;i<G[u].size();i++)//遍历u的所有子节点
    	{
    		v=G[u][i];
    		if(v==del)continue;//删点操作
    		if(!DFN[v])
    		{
    			tarjan(v);
    			Low[u]=Min(Low[u],Low[v]);
    		}
    		else if(instack[v])
    			Low[u]=Min(Low[u],DFN[v]);
    	}
    	if(DFN[u]==Low[u])
    		do
    		{
    			v=mystack.top();	mystack.pop();  instack[v]=false;
    			Tarjan[tar].push_back(v);
    		}while(u!=v);
    		tar++;
    		if(u==del){tar--;Tarjan[tar].clear();}
    }
    void InitTar(){
    	memset(DFN,0,sizeof(DFN));	memset(Low,0,sizeof(Low));
    	memset(instack,0,sizeof(instack));
    	while(!mystack.empty())mystack.pop();
    	for(int i=0;i<n;i++)Tarjan[i].clear();
    	tar=Time=0;
    }
    int Findmin(){
    	int ans=0;
    	for(int i=0;i<tar;i++)
    		ans=Max(ans,Tarjan[i].size());
    	if(ans<2)ans=0;
    	return ans;
    }
    int main(){
    	int i,j;
    	while(~scanf("%d%d",&n,&m)){
    		for(i=0;i<n;i++)G[i].clear();
    		while(m--)
    		{
    			int u,v;	scanf("%d %d",&u,&v);
    			G[u].push_back(v);
    		}
    		int minm=INF32;
    		for(i=0;i<n;i++)//i表示删去的点,注意不要把删掉的那个点当成一个强连通
    		{
    			InitTar();
    			del=i;
    			memset(vis,0,sizeof(vis));
    			for(j=0;j<n;j++)
    				if(!vis[j] && j!=del)
    					tarjan(j);
    
    			minm=Min(minm,Findmin());	if(!minm)break;
    		}
    		printf("%d
    ",minm);
    	}
    	return 0;
    }
    /*
    6 11
    0 1
    1 2
    2 3
    3 4
    4 0
    2 0
    3 1
    3 0
    4 1
    2 5
    5 3
    
    
    
    3 6
    0 1
    1 0
    1 2
    2 1
    0 2
    2 0
    
    ans:
    0 
    2
    */


  • 相关阅读:
    查找表包含的页和页所在的表
    一次死锁追踪经历
    SQL语句实现取消自增列属性
    如何修改SQL Server 2005服务器名称
    出身在二三线城市软件工作者的悲哀
    (转)Android 混淆器 ProGuard (一定程度防止反编译)
    《Java 并发编程实战》第一、二章阅读笔记
    在 Visual Studio 2010 中配置 OpenGL 开发环境
    《Java 学习笔记》 第七、八章阅读体验
    2012年上半年阅读书籍清单
  • 原文地址:https://www.cnblogs.com/james1207/p/3258028.html
Copyright © 2011-2022 走看看