Hdu 1296 迷宫城堡 (图论_强连通分量)

题目链接:http://acm.hdu.edu.cn/showproblem.php?pid=1269


题目大意:给定一个迷宫,问迷宫中的两个地点能否两两相连,顶点n<=1万,边m<=20万。


解题思路:Tarjan模板题。今天做树形DP的时候遇到双连通缩点,不会做,就来学习下图论的强连通分量和双连通分量,多学些新算法,对开拓思维也有好处。Tarjan算法的核心是通过一个深搜来实现,简单地说就是把后面遇到的连通的点往前面出现的点收缩,最后同一个强连通分量的所有点会收缩到一个点。如果设个low来标记他们属于哪个强连通分量,初始时他们low[i] = index最后同一个强连通分量的点的low[i]都会一样。详细的参见Here。

    Tarjan算法十分优美。 本题是用邻接表建图,操作起来略显麻烦,如果用vector会更加简洁。


测试数据:

1 0

4 3
1 2
2 3
3 1

3 3
1 2
2 3
3 1

3 4
1 2
2 1
2 3
3 2

3 3
1 2
2 3
3 2


代码:

#include <stdio.h>
#include <string.h>
#define MIN 10010
#define MAX 100011
#define min(a,b) (a)<(b)?(a):(b)


struct node {

	int v;
	node *next;
}*head[MAX],tree[MAX];
int num,index;
int n,m,top,st[MIN];
int isstack[MIN],vis[MIN];
int ptr,dfn[MIN],low[MIN];


void Initial() {

	top = 1,num = 0;
	index = ptr = 1;
	memset(dfn,0,sizeof(dfn));
	memset(head,NULL,sizeof(head));
	memset(isstack,0,sizeof(isstack));
}

void AddEdge(int x,int y) {

	tree[ptr].v = y;
	tree[ptr].next = head[x],head[x] = &tree[ptr++];
}
void Tarjan(int i){

	int j,v = -1;
	node *p = head[i];			//当前节点的邻接顶点
	st[++top] = i;				//将当前节点入栈
	isstack[i] = 1;				//标记已经入栈,栈内的点都是连通的,强连通待判断
	dfn[i] = low[i] = index++;  //这里记录出现的次序


	while (p != NULL) {			//遍历邻接顶点

		if (!dfn[p->v]) {		//如果顶点p->v未出现过

			Tarjan(p->v);		//往下搜索
			low[i] = min(low[i],low[p->v]);	//收缩到最小的那个点,此时p->v顶点的low已计算
		}
		else if (isstack[p->v])
			low[i] = min(low[i],dfn[p->v]);//收缩到最小的那个点,因为还在栈内low还未计算
		p = p->next;
	}


	if (dfn[i] == low[i]) {		//将属于i的那个强连通分量都出栈,都是i的人了..

		do {

			v = st[top--];
			isstack[v] = 0;
		}while (v != i);
		num++;
	}
	if (num > 1) return;
}


int main()
{
	int i,j,k,a,b;


	while (scanf("%d%d",&n,&m),n+m) {

		Initial();
		for (i = 1; i <= m; ++i) {

			scanf("%d%d",&a,&b);
			AddEdge(a,b);
		}


		for (i = 1; i <= n && num < 2; ++i)
			if (!dfn[i]) Tarjan(i);


		if (num == 1) printf("Yes\n");
		else printf("No\n");
	}
}

本文ZeroClock原创,但可以转载,因为我们是兄弟。

你可能感兴趣的:(算法,vector,struct,tree,测试,null)