popular cows:有向圖的強連通分量
阿新 • • 發佈:2018-11-15
tarjan演算法,即dfs找low和dfn,用timmer表示dfs的時間(經歷各個點的次序)
開始不明白怎麼進行縮點,後來發現就是染色,同一個顏色的點如果有連線到其他顏色的點就算出度不為0
如果出度為0的點(染色後)就一個,即為這個連通分量的所有點
如果有很多個,說明不存在被所有喜歡的牛(兩個出度為0的點不可能相互聯絡),為0
#include<iostream> #include<algorithm> #include<set> #include<stack> #include<vector> #include<string.h> #include<string> using namespace std; const int maxn1 = 10005; const int maxn2 = 50005; vector<int>G[maxn2]; stack<int>S; int N, M, color_num; int out[maxn1]; int color[maxn1],timeer,dfn[maxn1],low[maxn1]; int zerototal;//出度為0的縮點的個數 void dfs(int u) { S.push(u); low[u] = dfn[u] = timeer++; for (int i = 0; i < G[u].size(); i++) { int v= G[u][i];//下一個邊 if (!dfn[v])//是訪問而不是判棧中 { dfs(v); low[u] = min(low[u], low[v]); } else { low[u] = min(low[u], low[v]); } } if (dfn[u] == low[u]) { int v = 0; color_num++; while (v != u) { v = S.top(); S.pop(); color[v] = color_num;//染色類似縮點 } } } void cal() { for (int i = 1; i <= N; i++) { if (out[color[i]]) { continue; } for (int j = 0; j < G[i].size(); j++) { int v = G[i][j];//出結點 if (color[v] != color[i])//如果是連別的顏色 { out[color[i]] = true; } } } int tmp; for (int i = 1; i <= color_num; i++)//縮小之後的點數 { if (!out[i])//如果是練的自己 { zerototal++; tmp = i;//當前的出度為0的縮小之後的點 } } if (zerototal == 1) { int ans = 0; for (int i = 1; i <= N; i++) { if (color[i] == tmp) { ans++; } } cout << ans << endl; } else { printf("0\n"); } } int main() { timeer = 1; color_num = 0; zerototal = 0; memset(dfn, 0, sizeof(dfn)); memset(low, 0, sizeof(low)); memset(out, 0, sizeof(out)); cin >> N >> M; while (M--) { int be, ed; cin >> be >> ed; G[be].push_back(ed); } for (int i = 1; i <= N; i++) { if (!dfn[i]) { dfs(i); } } cal(); return 0; }