强联通分量targin模板(poj2186)

http://poj.org/problem?id=2186

//poj2186 强联通图模板 节点数1W 边数5W  79ms  G++  
#include<stdio.h>
const int sz = 50000+10; 
struct Edge
{
	int to;
	int next;
};
Edge edge[sz]; //存放边 
int head[sz]={0};//每个节点的第一条边的编号 
int n,m;//有n个节点,m条边 
int cnt;//边的编号 

int stack[sz];//栈 
int top;
int dfn[sz]={0},low[sz]={0};//targin要用的变量 
bool instack[sz]={false};//是否存在栈中 
int c = 0;//递增量 ,时间戳 
int sc = 0 ;//一共有多少个联通分量
int count[sz]={0};//每个联通分量有多少个节点 
int min(int a,int b)
{
	return a<b?a:b;
}
void targin(int u)
{
	low[u]=dfn[u]=++c; //时间戳 
//	s.push(u);
	stack[top++] = u;//入栈 
	instack[u]=true;
	for(int i=head[u];i;i=edge[i].next)
	{
		int v = edge[i].to;
		if(dfn[v]==0) targin(v);
		if(instack[v])low[u] = min(low[u],low[v]);
	}	
	if(dfn[u]==low[u])
	{
		sc++;
		int v;
		do 
		{
			v = stack[--top];//出栈 
			instack[v]=false;//标记 
			count[sc]++;//这个联通分量的节点数加1
			low[v] = sc;//记录节点v属于哪一个联通分量 
		}while(v!=u);
	}
}
void addEdge(int u,int v)
{
	edge[++cnt].next=head[u];
	edge[cnt].to = v;
	head[u] = cnt;
}
void solve()//输出结果 
{
	int out[sz]={0};
	for(int i=1;i<=n;i++)
	{
		for(int j=head[i];j;j=edge[j].next)
		{
			if(low[i]!=low[edge[j].to])
			{
				out[low[i]]=1;
				break;	
			}	
		}	
	}	
	int c = 0;
	int id;
	for(int i=1;i<=sc;i++)
	{
		if(out[i]==0) //如果出度为0 
		{
			c ++ ;
			if(c>1){
				printf("0\n");
				return ;
			}
			id = i;
		}
	}
	printf("%d\n",count[id]);
}
void init()
{
	sc = cnt = top = 0;
	for(int i=1;i<=n;i++)
	{
		dfn[i]=low[i]=head[i]=count[i]=0;
		instack[i]=false;
	}
}
int main()
{
	scanf("%d %d",&n,&m);
	init();
	for(int i=1;i<=m;i++)
	{
		int u,v;
		scanf("%d %d",&u,&v);
		addEdge(u,v);
	}
	
	for(int i=1;i<=n;i++)//不联通 
	{
		if(dfn[i]==0)
		{
			targin(i);
		}
	}
	solve();
	return 0;
}

    强联通图缩点后:得到一个DAG(有向无环图),得到这个DAG我们可以处理一些问题:
    1.问:是否存在某些点(point1或point2 。。。。。),使得 所有的点是否可以汇聚到这个点(point1 或 point2 。。。。。)上,比如3个点1 2 3 ,1-->2  2-->1  2-->3 画图可知 1 2 都可以汇聚到3上面,
      问题可以转化为 一共有多少个出度为0 的强连通图 ,如果只有1个,则结果就是该连通图的节点数,如果>1 ,则没有。因为最终的DAG,如果有2个强联通图没有出度,
      则必定有一个点 得不到另外一个点的汇聚。
    2.问:有一个消息,如果A 到B右一条有向边A-->B,则A可以把消息传给B,问我们至少需要选择多少个点,作为信息的源点,最终可以使得每一个节点都获得该 消息
      问题转化为: 一共有多少个节点没有入度,因为没有入度的点没有消息来源,我们需要选择它作为源点
    3.问: 我们至少需要添加多少条有向边,才可以使得整个图为强联通图
      问题转化为: 计算得到 入度为0的强联通图个数 in0 , 计算得到出度为0的强联通图的个数 out0,然后结果就是max(in0,out0)。因为强联通图必然是每个点都有出度和入度,
      所以我们必须为没有入度或者出度的点 连边,那么最少就需要max(in0,out0)条边。
       

猜你喜欢

转载自blog.csdn.net/zark721/article/details/80287004