POJ-2553 The Bottom of a Graph (Tarjan強聯通+縮點)

題目連接

題意:  一個有向圖,然後讓你求這個圖的底部(求出所有沒有出度的強聯通分量),如果沒有底部輸出空行,升序輸出

數據範圍:n < 5000 

思路:

       Tarjan縮點後,判斷某個點是否有出度,找到出度爲0的點,把這個點(縮點後的點,縮點前是強聯分量),把這個點內的所有點升序輸出

AC代碼:

/*
	Tarjan 縮點 
	我們既然能在有向圖中找到環,那麼我們就可以吧環給縮成點了(利用Tarjan縮點),
	縮點基於一種染色實現,在DFS搜索的過程中,嘗試吧屬於同一個強連通分量的點都染成一個顏色,
	同一顏色的點就相當於一個點, 
	
	縮點的實際作用:把一個有向帶環圖,變成一個有向無環圖(DAG) ,
	這樣基於DAG的算法就能跑了,
	可以算縮點後出度爲0的點。 
	步驟:1)Tarjan縮點,2)染色處理,3)建有向無環圖 (DAG) 
	
	怎麼實現染色呢?引入一個color數組,把同一強連通分量的顏色都染上同一顏色(標記爲同一值)  
*/
#include<iostream>
#include<math.h>
#include<cstring>
#include<algorithm>
#include<stack>
using namespace std;
const int MAXN = 5e3 + 20;
const int MAXM = 1e6 + 10; 
int head[MAXN], cnt, tot, dfn[MAXN], low[MAXN], color[MAXN], col;
bool vis[MAXN];
int degree[MAXN];
stack<int> stc;
int n, m;
struct Edge {
	int to, next, dis;	
}edge[MAXM << 1];
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) {
	vis[x] = 1;
	dfn[x] = low[x] = ++tot;
	stc.push(x);
	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]);
		}
	}
	if(dfn[x] == low[x]) {
		col ++;
		while(true) {
			int top = stc.top();
			stc.pop();
			color[top] = col;	//顏色相同的點縮點 
			vis[top] = 0;
		//	cout << top << " ";
			if(top == x) break; 
		}
		//cout << endl;
	}
}
void solve(){
	for(int i = 1; i <= n; ++i) {
		if(!dfn[i])
			Tarjan(i);
	}
	
	for(int x = 1; x <= n; ++x) {	//遍歷 n個節點 
		for(int i = head[x]; i; i = edge[i].next) {	//縮點後  每個點的出度 
			int to = edge[i].to;
			if(color[x] != color[to]) {
				degree[color[x]] ++;
			}
		}
	}
	int q = 0;
	int ans[MAXN];
	for(int i = 1; i <= col; ++i) {
		if(degree[i] > 0) continue;
		for(int j = 1; j <= n; ++j) {
			if(color[j] == i) {
				ans[q++] = j;
			}
		}
	}
	sort(ans, ans + q);
	for(int i = 0; i < q; ++i) {
		if(i == 0) cout  << ans[i];
		else cout << " " << ans[i]; 
	}
	cout << endl;
}
void init () {
	cnt = 1;
	tot = 0;
	col = 0;
	memset(vis, 0, sizeof(vis));
	memset(head, 0, sizeof(head));
	memset(dfn, 0, sizeof(dfn));
	memset(low, 0, sizeof(low));
	memset(degree, 0, sizeof(degree));
	memset(color, 0, sizeof(color));
	while(!stc.empty()) stc.pop();
}
int main () {
	std::ios::sync_with_stdio(false);
	cin.tie(0);
	while(cin >> n && n) {
		cin >> m;
		init();
		int x, y;
		for(int i = 1; i <= m; ++i) {
			cin >> x >> y;
			add_edge(x, y, 0);
		}
		solve();
	} 
	return 0;
}

 

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章