您的位置:首页 > 其它

HDU - 1269 迷宫城堡

2015-03-21 00:19 260 查看
迷宫城堡

Time Limit: 1000MSMemory Limit: 32768KB64bit IO Format: %I64d & %I64u
Submit Status

Description

为了训练小希的方向感,Gardon建立了一座大城堡,里面有N个房间(N<=10000)和M条通道(M<=100000),每个通道都是单向的,就是说若称某通道连通了A房间和B房间,只说明可以通过这个通道由A房间到达B房间,但并不说明通过它可以由B房间到达A房间。Gardon需要请你写个程序确认一下是否任意两个房间都是相互连通的,即:对于任意的i和j,至少存在一条路径可以从房间i到房间j,也存在一条路径可以从房间j到房间i。



Input

输入包含多组数据,输入的第一行有两个数:N和M,接下来的M行每行有两个数a和b,表示了一条通道可以从A房间来到B房间。文件最后以两个0结束。



Output

对于输入的每组数据,如果任意两个房间都是相互连接的,输出"Yes",否则输出"No"。



Sample Input

3 3
1 2
2 3
3 1
3 3
1 2
2 3
3 2
0 0




Sample Output

Yes
No




#include <iostream>
#include <vector>
#include <stack>
#include<algorithm>
                         //此题为Tarjan算法求强连通分量的模板题
using namespace std;
const int MAX = 10000 + 10;
int n;
vector <int> v[MAX];             //用邻接表表示有向线段
stack <int> s;                   //Tarjan算法中的栈
int mark_stack[MAX];             //标记是否在栈中
int dfn[MAX];                    //dfn[u]为节点u深度优先搜索的次序编号
int low[MAX];                    //low[u]为u或u的子树可以追溯到的最早的栈中节点的次序号
int time;
int sum;                       //连通分支数

void Tarjan(int rank)
{
	dfn[rank] = low[rank] = ++time;
	s.push(rank);          //把rank压入栈
	mark_stack[rank] = 1;  //标记其在栈中
	int i;
	
	for (i = 0; i < v[rank].size(); i++) //搜索rank的所有节点
	{
		if (!dfn[v[rank][i]]) //如果没搜索过
		{
			Tarjan(v[rank][i]);    //Tarjan这个节点
			low[rank] = min(low[rank], low[v[rank][i]]); //更新rank可追溯到的最早节点
		}
		else
		{
			if (mark_stack[v[rank][i]]) //在栈中
			{
				low[rank] = min(low[rank], dfn[v[rank][i]]); //更新rank可追溯到的最早节点
			}
		}
	}
	if (low[rank] == dfn[rank])      //dfn[u]=low[u]表示以u为节点的搜索子树上的所有节点是一个强连通分量
	{
		sum++;                       //连通分支量增加
		int x = s.top();
		mark_stack[x] = 0; 
		s.pop();
		while (x != rank)           //rank及其上的退栈,成一个连通分支
		{
			x = s.top();
			mark_stack[x] = 0;
			s.pop();
		}
	}
}

int main()
{
	int m;
	while (cin >> n >> m, n + m)
	{
		while (!s.empty())     //初始化清空栈
		{
			s.pop();
		}
		int i;
		for (i = 0; i<MAX; i++)      //初始化邻接表
		{
			v[i].clear();
		}
		memset(dfn, 0, sizeof(dfn));     //初始化仨数组
		memset(low, 0, sizeof(low));
		memset(mark_stack, 0, sizeof(mark_stack));
		
		while (m--)    //构建邻接表v[u]中为以u为起点的线段指向的终点
		{
			int x, y;
			cin >> x >> y;
			v[x].push_back(y);
		}

		sum = 0;
		time = 0;
		for (i = 1; i <= n; i++) 
		{
			if (!dfn[i])     //如果未搜索过
			{
				if (sum)    //如果已得到一个连通分支
				{
					sum++;
					break;
				}
				else
				{
					Tarjan(1);    
				}
			}

		}
		if (sum == 1)
		{
			cout << "Yes" << endl;
		}
		else
		{
			cout << "No" << endl;
		}
	}
	return 0;
}
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: