HDU-1269(Tarjan模板-求强连通分量)

题目连接

题意:

        求一个有向图n个点 m 条边,是否是强连通分量,如果是输出Yes, 不是输出No.

数据范围

        n < 10000,  m < 100000

思路:

        Tarjan模板题

补习:

AC code:

/*
	Tarjan求有向图的强连通分量,  
*/ 
#include<iostream>
#include<cstring> 
#include<stdio.h>
#include<math.h>
#include<stack>
using namespace std;
const int MAXN = 1e5 + 10;
struct Edge{
	int to, next, dis;
}edge[MAXN << 1];
int head[MAXN], cnt, ans; 
bool vis[MAXN]; 
//dfn 第一次访问到该节点的时间(时间戳)
//low[i] low[i]能从哪个点(最早时间戳)到达这个点的。 
int dfn[MAXN], low[MAXN], tot;	
stack<int> stc;
void add_edge(int u, int v, int dis) {
	edge[++cnt].to = v;
	edge[cnt].next = head[u];
	head[u] = cnt;
}
void Tarjan(int x) {
	dfn[x] = low[x] = ++tot;
	stc.push(x);
	vis[x] = 1;
	for(int i = head[x]; i; i = edge[i].next) {
		int to = edge[i].to;
		if ( !dfn[to] ) {
			Tarjan(to);
			low[x] = min(low[x], low[to]);
		} else if (vis[to]){
			low[x] = min(low[x], dfn[to]);
		}
	}
	//cout << x << " " << low[x] << " " << dfn[x] << endl;
	if(low[x] == dfn[x]) {	//发现是整个强连通分量子树里 的最小根。
		//int cnt = 0;
		ans++;	//强连通分量计数器 
		while(1) {
			int top = stc.top();
			stc.pop();
			//cnt ++;
			vis[top] = 0;
			//cout << top << " "; 每个强连通分量内的点 
			if(top == x) break;
		} 
	}
}
void init() {
	cnt = 1;
	tot = 0;
	ans = 0;
	memset(vis, 0, sizeof(vis));
	memset(head, 0, sizeof(head));
	memset(dfn, 0, sizeof(dfn));
	memset(low, 0, sizeof(low));
	while(!stc.empty()){
		stc.pop();
	}
}
int main () {
	std::ios::sync_with_stdio(false);
	cin.tie(0);
	int n, m;
	while(cin >> n >> m && (n || m)){
		init();
		int x, y;
		for(int i = 1; i <= m; ++i) {
			cin >> x >> y;
			add_edge(x, y, 0);	//有向图求强连通 
		} 
		for(int i = 1; i <= n; ++i) {
			if( !dfn[i] )
				Tarjan(i);
		} 
		if(ans == 1) {
			cout << "Yes" << endl;
		} else {
			cout << "No" << endl; 
		}
	}
	return 0;
} 

发布了199 篇原创文章 · 获赞 156 · 访问量 7万+

猜你喜欢

转载自blog.csdn.net/Harington/article/details/105448394
今日推荐