POJ2762 Going from u to v or from v to u?(强连通分量缩点+拓扑排序)

题意是给出一些点,和他们之间的有向边,如果图中任意两点 x,y 之间满足 x 可以到达 y 或者 y 可以到达 x ,就输出“Yes”,否则输出“No”,注意,这里是 x 到达 y ,或者 y 到达 x ,是 或者 不是 而且 !!!

如果是“而且”的话,很明显的是判断整个图是否为一个强连通分量(例如 HDU1269 迷宫城堡,该题的解题报告),那么就简单的多了,但是这个题不行。

处理方法(来自 LC 以及 POJ 的discuss):先用强连通缩点来化简图,然后在图上做拓扑排序,如果排序过程中,出现1个以上的点入度同时为0时,那么就不满足条件。


tarjan算法实现:

#include
#include
#include
using namespace std;

const int N = 1001;

struct Edge{
	int s,e,next;
}edge1[6*N],edge2[6*N];

int n,m,e_num1,e_num2,vis_num,cnt;
int head[N],instack[N],low[N],tim[N],belong[N],de[N];

void AddEdge(int a,int b,Edge edge[],int &e_num){
	edge[e_num].s=a; edge[e_num].e=b; edge[e_num].next=head[a]; head[a]=e_num++;
}

void getmap(){
	int a,b;
	scanf("%d%d",&n,&m);
	e_num1=0;
	memset(head,-1,sizeof(head));
	while(m--){
		scanf("%d%d",&a,&b);
		AddEdge(a,b,edge1,e_num1);
	}
}

stack  st;
void tarjan(int x){
	int j;
	tim[x]=low[x]=++vis_num;
	instack[x]=1;
	st.push(x);
	for(j=head[x];j!=-1;j=edge1[j].next){
		int u=edge1[j].e;
		if(tim[u]==-1){
			tarjan(u);
			if(low[x]>low[u])low[x]=low[u];
		}
		else if(instack[u] && low[x]>tim[u])low[x]=tim[u];
	}
	if(low[x]==tim[x]){
		cnt++;
		do{
			j=st.top();
			st.pop();
			instack[j]=0;
			belong[j]=cnt;
		}while(j!=x);
	}
}

int topo()
{
	int i,cur,u,count,num;
	count=0;
	for(i=1;i<=cnt;i++){
		if(de[i]==0){
			cur=i;count++;
		}
	}
	if(count>1)return 0;
	num=cnt;
	while(num--){
		count=0;
		for(i=head[cur];i!=-1;i=edge2[i].next){
			u=edge2[i].e;
			de[u]--;
			if(de[u]==0){
				count++;cur=u;
			}
		}
		if(count>1)return 0;
	}
	return 1;
}

void solve(){
	int i;
	cnt=vis_num=0;
	memset(instack,0,sizeof(instack));
	memset(low,0,sizeof(low));
	memset(tim,-1,sizeof(tim));
	for(i=1;i<=n;i++){
		if(tim[i]==-1)tarjan(i);
	}
	
	e_num2=0;
	memset(head,-1,sizeof(head));
	memset(de,0,sizeof(de));
	for(i=0;i


你可能感兴趣的:(图论,struct,算法,ie)