POJ-2553 The Bottom of a Graph (Tarjan Strong Unicom + contraction point)

Topic connection

Topic: A directed graph, and then let you find the bottom of the graph (find all the strong connected components that have no outgoing degrees). If there are no blank lines at the bottom, the output will be in ascending order.

Data range: n <5000 

Ideas:

       After Tarjan shrinks the point, determine whether a certain point has an outgoing degree, find a point with an outgoing degree of 0, put this point (the point after the abbreviated point, the strong link component before the abbreviated point), and output all points within this point in ascending order

AC code:

/*
	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;
}

 

Published 200 original articles · praised 157 · 70,000 views

Guess you like

Origin blog.csdn.net/Harington/article/details/105478138