P2341 [HAOI2006]受歡迎的牛(tarjan + 縮點 )
阿新 • • 發佈:2018-12-30
題目背景
本題測試資料已修復。
題目描述
每頭奶牛都夢想成為牛棚裡的明星。被所有奶牛喜歡的奶牛就是一頭明星奶牛。所有奶
牛都是自戀狂,每頭奶牛總是喜歡自己的。奶牛之間的“喜歡”是可以傳遞的——如果A喜
歡B,B喜歡C,那麼A也喜歡C。牛欄裡共有N 頭奶牛,給定一些奶牛之間的愛慕關係,請你
算出有多少頭奶牛可以當明星。
輸入輸出格式
輸入格式:
第一行:兩個用空格分開的整數:N和M
第二行到第M + 1行:每行兩個用空格分開的整數:A和B,表示A喜歡B
輸出格式:
第一行:單獨一個整數,表示明星奶牛的數量
輸入輸出樣例
輸入樣例#1: 複製
3 3 1 2 2 1 2 3
輸出樣例#1: 複製
1
說明
只有 3 號奶牛可以做明星
【資料範圍】
10%的資料N<=20, M<=50
30%的資料N<=1000,M<=20000
70%的資料N<=5000,M<=50000
100%的資料N<=10000,M<=50000
思路:顯然一個強聯通分量裡面的所有的點都是滿足要求的,我們先來一遍tarjan進行縮點,然後圖就變成了一個有向無環圖,那麼我們直接在這個DAG圖中找出出度為0的點,該點就是我們要求的點,如果這種點存在倆個,說明不存在所有的牛都崇拜的牛,直接輸出0,如果存在一個,那麼考慮到這個點可能是縮點以後的點,所以我們只要輸出該縮點內部的點便可以了,具體見程式碼
#include<iostream> using namespace std; const int maxn = 50010; int head[maxn], num[maxn], dfn[maxn], low[maxn], Stack[maxn], vis[maxn], ans[maxn], result[maxn], belong[maxn]; int n, m, cnt = 1, a, b, total, sum = 0, index; struct node { int to; int next; }edge[2 * maxn]; void add(int u, int v) { edge[cnt].to = v; edge[cnt].next = head[u]; head[u] = cnt++; } void tarjan(int u) { dfn[u] = low[u] = ++total; vis[u] = 1; Stack[++index] = u; for (int i = head[u]; i != 0; i = edge[i].next) { int v = edge[i].to; if (!dfn[v]) { tarjan(v); low[u] = min(low[u], low[v]); } else if (vis[v]){ low[u] = min(low[u], dfn[v]); } } if (low[u] == dfn[u]) { sum++; do { int p = Stack[index--]; vis[p] = 0; belong[p] = sum; } while (Stack[index + 1] != u); } } int main() { cin >> n >> m; for (int i = 0; i < m; i++) { cin >> a >> b; add(a, b); } for (int i = 1; i <= n; i++) { if (!dfn[i]) { tarjan(i); } } for (int i = 1; i <= n; i++) { ans[belong[i]]++; for (int j = head[i]; j != 0; j = edge[j].next) { int v = edge[j].to; if (belong[i] != belong[v]) result[belong[i]]++;//這一步是用來判斷縮點的出度的 } } int num = 0; for (int i = 1; i <= sum; i++) { if (!result[i]) { if (num) { cout << 0 << endl; return 0; } num = i; } } cout << ans[num] << endl; return 0; }