POJ-2553 La parte inferior de un gráfico (punto de contracción Tarjan Strong Unicom +)

Conexión de tema

Tema: Un gráfico dirigido, y luego le permite encontrar la parte inferior del gráfico (encuentre todos los componentes conectados fuertes que no tienen grados salientes). Si no hay líneas en blanco en la parte inferior, la salida estará en orden ascendente.

Rango de datos: n <5000 

Ideas:

       Después de que Tarjan reduzca el punto, determine si un determinado punto tiene un grado saliente, encuentre un punto con un grado saliente de 0, coloque este punto (el punto después del punto abreviado, el componente de enlace fuerte antes del punto abreviado) y envíe todos los puntos dentro de este punto en orden ascendente

Código 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;
}

 

Publicó 200 artículos originales · elogió 157 · 70,000 visitas

Supongo que te gusta

Origin blog.csdn.net/Harington/article/details/105478138
Recomendado
Clasificación