[POI2004] SZP (貪心+拓撲排序)
阿新 • • 發佈:2018-11-09
【問題描述】 Byteotian 中央情報局(BIA) 僱傭了許多特工. 他們每個人的工作就是監視 另一名特工. Byteasar 國王需要進行一次祕密行動,所以他要挑選儘量多的信得過的特工. 但 是這項任務是如此的機密以至於所有參加行動的特工都必須至少被另一名沒有 參加任務的特工所監視(就是說如果某個特工參加了行動,那麼原先監視他的那些 特工中至少要有一個沒有參加進行動). 給出監視任務的詳情,要求計算最多能有 多少個特工參與其中. 【輸入格式】 第一行只有一個整數, n – 特工的總數, 2 <= n <= 1000000. 特工從1 到n 編號. 接下來n 行每行一個整數ak 表示特工k 將要監視特工ak , 1 <= k <= n, 1 <= ak <= n, ak <> k. 【輸出格式】 列印一個數,最多能有多少特工參加入這個任務. 【樣例輸入】 6 2 3 l 3 6 5 【樣例輸出】 3
每個點的出度都為\(1\),很容易看出是基環外向樹然而並沒有用
貪心+拓撲排序,如果一個點不選,則他的兒子一定要選。
最後還剩下環,隨便找個位置拆開就行了。
#include <cstdio> #define Open(s) freopen(s".in","r",stdin);freopen(s".out","w",stdout); #define Close fclose(stdin);fclose(stdout); namespace IO{ int xjc; char ch; inline int read(){ xjc = 0; ch = getchar(); while(ch < '0' || ch > '9') ch = getchar(); while(ch >= '0' && ch <= '9'){ xjc = xjc * 10 + ch - '0'; ch = getchar(); } return xjc; } }using namespace IO; inline int min(int a, int b){ return a > b ? b : a; } const int MAXN = 1000010; struct Queue{ int s[MAXN]; int head, tail; inline void push(int x){ s[++tail] = x; } inline int pop(){ return s[++head]; } inline int size(){ return tail - head; } }q; int n, a[MAXN], ans, vis[MAXN], in[MAXN]; //vis為1表示不選,為2表示選 int main(){ Open("szp"); n = read(); for(int i = 1; i <= n; ++i) ++in[a[i] = read()]; for(int i = 1; i <= n; ++i) if(!in[i]) vis[i] = 1, q.push(i); while(q.size()){ int now = q.pop(); if(vis[now] == 1) vis[a[now]] = 2; if(!(--in[a[now]])){ q.push(a[now]); if(!vis[a[now]]) vis[a[now]] = 1; } } for(int i = 1; i <= n; ++i){ //找剩下的環 if(!vis[i]){ int now = a[i], pos = i; while(now != i){ if(vis[now]){ pos = now; break; } now = a[now]; } q.push(pos); } } while(q.size()){ int now = q.pop(); if(vis[now] == 1 && !vis[a[now]]) vis[a[now]] = 2; if(!(--in[a[now]])){ q.push(a[now]); if(!vis[a[now]]) vis[a[now]] = 1; } } for(int i = 1; i <= n; ++i) if(vis[i] == 2) ++ans; printf("%d\n", ans); return 0; }