POJ 2553 The Bottom of a Graph 强联通分量

来源:http://poj.org/problem?id=2553

题意:题目新给了一个定义,在一个图中,若从点v能够到达点w,且从w能够到达点v,则称v为sink。让输出一个图中sink的序号,按升序输出。

思路:首先根据定义,易知,因为是有向图,所以一个孤立的强联通分量里面的点都是sink,这点很容易理解,因为强联通分量里面的点都是互达的。而且该强联通分量是孤立的,也就是说,该强联通分量缩点后的出度为0。即缩点后该点到不了其他点,满足sink的定义。也就是说,该题就是求缩点后哪些点的出度为0,即为答案。

代码:

#include <iostream>
#include <cstdio>
#include <algorithm>
#include <string.h>
#include <vector>
using namespace std;

#define CLR(arr,val) memset(arr,val,sizeof(arr))
const int N = 5010;
int low[N],dfn[N],numnode,numedge,head[N],numpath;
int timeorder,ss[N],numss,vis[N],numQ[N],numcnt;
int outdegree[N];
vector<int> vv[N];
struct edge{
	int x,y,next;
}ee[N * N];
void add_edge(int lp,int rp){
	ee[numedge].x = lp;
	ee[numedge].y = rp;
	ee[numedge].next = head[lp];
	head[lp] = numedge++;
}
int min(int a,int b){
	return a < b ? a : b;
}
void targin(int x){
	vis[x] = 1;
	timeorder++;
	numss++;
	dfn[x] = low[x] = timeorder;
	ss[numss] = x;
	for(int i = head[x]; i != -1; i = ee[i].next){
	   int rp = ee[i].y;
	   if(!vis[rp]){
	     targin(rp);
		 low[x] = min(low[x],low[rp]);
	   }
	   else if(vis[rp] == 1){
	     low[x] = min(low[x],dfn[rp]);
	   }
	}
	if(low[x] == dfn[x]){
	   numcnt++;
	   while(1){
	     int tt = ss[numss--];
		 vis[tt] = 2;
		 numQ[tt] = numcnt;
		 vv[numcnt].push_back(tt);
		 if(tt == x)
			 break;
	   }
	}
}
void init(){
	CLR(low,0);
	  CLR(dfn,0);
	  CLR(head,-1);
	  CLR(ss,0);
	  CLR(vis,0);
	  CLR(numQ,0);
	  CLR(outdegree,0);
	  CLR(vv,0);
	  timeorder = 0;
	  numss = 0;
	  numedge = 0;
	  numcnt = 0;
}
int main(){
	//freopen("1.txt","r",stdin);
	while(scanf("%d",&numnode) && numnode){
	  scanf("%d",&numpath);
	  init();
	  int lp,rp;
	  for(int i = 0; i < numpath; ++i){
	     scanf("%d%d",&lp,&rp);
		 add_edge(lp,rp);
	  }
	  for(int i = 1; i <= numnode; ++i){
	     if(!dfn[i])
			 targin(i);
	  }
	 // printf("numcnt = %d\n",numcnt);
	  for(int i = 0 ;i < numedge; ++i){
	    int leftp = numQ[ee[i].x];
		int rightp = numQ[ee[i].y];
		if(leftp != rightp){
		  outdegree[leftp]++;
		}
	  }
	  int ans[N], K = 0;
	  for(int i = 1; i <= numcnt; ++i){
		  if(!outdegree[i]){
			  for(int j = 0;j < vv[i].size(); ++j){
			    ans[K++] = vv[i][j];
			  }
		  }
	  }
	  sort(ans,ans+K);
	  for(int i = 0; i < K-1; ++i)
		  printf("%d ",ans[i]);
	  printf("%d\n",ans[K-1]);
	}
	return 0;
}


评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值