1. 程式人生 > >【poj2553】The Bottom of a Graph(強連通分量縮點)

【poj2553】The Bottom of a Graph(強連通分量縮點)

targe ring sin spa const ostream 連通 stream pty

題目鏈接:http://poj.org/problem?id=2553

【題意】

給n個點m條邊構成一幅圖,求出所有的sink點並按順序輸出。sink點是指該點能到達的點反過來又能回到該點。

【思路】

不難想象sink點一定是在強連通分量中,而且強連通分量縮點後出度為0,就可以說明該強連通分量內所有的點都是sink點。

之前wa了一發是因為寫成了out[i],註意是從縮點構成的dag中找出度為0的點,而不是從原來的圖中找。

【ac代碼】

#include <cstdio>
#include <iostream>
#include <algorithm>
#include 
<stack> #include <vector> #include <cstring> using namespace std; const int N = 5005; int low[N], vis[N], dfn[N], col[N], out[N], ans[N]; vector<int>V[N]; stack<int>s; int n, cnt, num; void dfs(int u) { s.push(u); vis[u] = 1; dfn[u] = low[u] = ++cnt;
for (int i = 0; i < V[u].size(); i++) { int v = V[u][i]; if (!dfn[v]) { dfs(v); low[u] = min(low[u], low[v]); } else if (vis[v]) low[u] = min(low[u], dfn[v]); } if (low[u] == dfn[u]) {
int t; num++; do { t = s.top(); s.pop(); col[t] = num; vis[t] = 0; } while (t != u); } } void tarjan() { int i; memset(dfn, 0, sizeof(dfn)); memset(low, 0, sizeof(low)); memset(vis, 0, sizeof(vis)); memset(col, 0, sizeof(col)); while (!s.empty()) s.pop(); cnt = num = 0; for (i = 1; i <= n; i++) if (!dfn[i]) dfs(i); } int main() { int m, i, j; while(scanf("%d", &n), n) { scanf("%d", &m); for(i = 1; i <= n; i++) V[i].clear(); int a, b; while(m--) { scanf("%d%d", &a, &b); V[a].push_back(b); } tarjan(); memset(out, 0, sizeof out); for(i = 1; i <= n; i++) for(j = 0; j < V[i].size(); j++) { int v = V[i][j]; if(col[i] != col[v]) out[col[i]]++;//該顏色出度+1 } cnt = 0; for(i = 1; i <= n; i++) if(!out[col[i]]) ans[++cnt] = i; sort(ans+1, ans+1+cnt); for(i = 1; i < cnt; i++) printf("%d ", ans[i]); printf("%d\n", ans[cnt]); } return 0; }

【poj2553】The Bottom of a Graph(強連通分量縮點)