题目连接
题意: 一个有向图,然后让你求这个图的底部(求出所有没有出度的强联通分量),如果没有底部输出空行,升序输出
数据范围: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;
}