tarjan 受歡迎的牛
阿新 • • 發佈:2018-12-30
既然愛慕關係可以傳遞,那麼將互相可達的某幾個點縮成一個點,就能簡化原圖了,
那麼很自然想到tarjan求強連通分量
那麼就只需找到可以被所有縮點遍歷到的那個縮點
再輸出它所含的點數就行了
先用tarjan將所有聯通分量進行縮點,縮點後考慮出度為0的點的個數:
(1)個數大於1的時候,顯然不存在受歡迎的牛!
(2)個數等於0的時候,假設有一頭牛X是受歡迎的,那麼它必定有喜歡的牛Y,而它又收到牛Y的歡迎,說明存在環,不是DAG圖,矛盾!
(3)個數等於1的時候,用數學歸納法推一下,有這樣一個結論:出度為0的那個點可以被其它所有點到達
#include <iostream> #include <cstdio> #include <cstring> #include <cmath> const int maxm=5e4+5; int n, m, a, b, cnt, num, top, col; int head[maxm]; int s[maxm]; int st[maxm]; int co[maxm]; int de[maxm]; int dfn[maxm], low[maxm]; using namespace std; struct cow { int to; int next; } edge[maxm]; void add(int x, int y) { cnt++; edge[cnt].to = y; edge[cnt].next = head[x]; head[x] = cnt; } void tarjan(int u) { dfn[u] = low[u] = ++num; st[++top] = u; for (int i = head[u]; i; i = edge[i].next) { int v = edge[i].to; if (dfn[v] == 0) { tarjan(v); low[u] = min (low[u], low[v]); } else if(co[v] == 0) low[u] = min (low[u], low[v]); } if (low[u] == dfn[u]) { co[u] = ++col; ++s[col]; while (st[top] != u) { ++s[col]; co[st[top]] = col; --top; } --top; } } int main() { scanf("%d%d", &n, &m); for (int i = 1; i <= m; i++) { scanf("%d%d", &a, &b); add(b, a); //倒著存以最後統計出度而不是統計入度 } for (int i = 1; i <= n; i++) if (!dfn[i]) tarjan (i); for (int i = 1; i <=n; i++) for (int j = head[i]; j; j = edge[j].next) { int v = edge[j].to; if (co[i] != co[v]) de[co[v]]++; } int ans = 0, u = 0; for (int i = 1; i <= col; i++) if(de[i] == 0) { ans = s[i]; u++; } if(u == 1) printf("%d\n", ans); else printf("0\n"); return 0; }
void tarjan(int 當前點) { 這個點的low=dfn=時間戳; 將這個點入棧; 標記這個點入棧; 列舉這個點連線的所有邊 { 如果目標點沒有被訪問過 { tarjan(目標點); 更新當前點的low; } 如果目標點被訪問過 { 更新當前點的low; } } 如果當前點的low==dfn { 將這個點及棧以上的點出棧,標記成一個強連通分量; ans++; } }