1. 程式人生 > >[NOIP2015] 信息傳遞

[NOIP2015] 信息傳遞

bsp type 兩種 必須 www. font init ems min

嘟嘟嘟

題面很清楚,就是讓求最小環。

有兩種做法:

F1:用帶權並查集。將每一條邊連接的兩個點所在集合合並,如果已經在一個集合,說明形成了環,用dis[x] + dis[y] + 1更新ans。因為圖中的邊是有向的,所以並查集也必須又向,對於邊(x->y),可以規定x所在集合向y和並,那麽同時dis[x] = dis[y] + 1。

F2:拓撲排序,先刪去所有入度為0的點,因為這些點肯定不在環中。然後把這些點連接著的點的入度-1,繼續刪去所有入度為0的點。最後的圖一定是一個只有簡單環且不連通的圖,因為題中說每一個點出度為1。對於每一個環,dfs求大小即可。

這裏給出F1的代碼。

技術分享圖片
 1 #include<cstdio>
 2 #include<iostream>
 3 #include<cmath>
 4 #include<algorithm>
 5 #include<cstring>
 6 #include<cstdlib>
 7 #include<cctype>
 8 #include<vector>
 9 #include<stack>
10 #include<queue>
11 using namespace std;
12 #define enter puts("") 
13
#define space putchar(‘ ‘) 14 #define Mem(a, x) memset(a, x, sizeof(a)) 15 #define rg register 16 typedef long long ll; 17 typedef double db; 18 const int INF = 0x3f3f3f3f; 19 const db eps = 1e-8; 20 const int maxn = 2e5 + 5; 21 inline ll read() 22 { 23 ll ans = 0; 24 char ch = getchar(), last =
; 25 while(!isdigit(ch)) last = ch, ch = getchar(); 26 while(isdigit(ch)) ans = (ans << 1) + (ans << 3) + ch - 0, ch = getchar(); 27 if(last == -) ans = -ans; 28 return ans; 29 } 30 inline void write(ll x) 31 { 32 if(x < 0) x = -x, putchar(-); 33 if(x >= 10) write(x / 10); 34 putchar(x % 10 + 0); 35 } 36 37 int n, ans = INF; 38 39 int p[maxn], dis[maxn]; 40 void init() 41 { 42 for(int i = 1; i <= n; ++i) p[i] = i; 43 } 44 int Find(int x) 45 { 46 if(x != p[x]) 47 { 48 int las = p[x]; 49 p[x] = Find(p[x]); 50 dis[x] += dis[las]; 51 } 52 return p[x]; 53 } 54 void merge(int x, int y) 55 { 56 int px = Find(x), py = Find(y); 57 if(px != py) p[px] = py, dis[x] = dis[y] + 1; 58 else ans = min(ans, dis[x] + dis[y] + 1); 59 } 60 61 int main() 62 { 63 n = read(); 64 init(); 65 for(int i = 1; i <= n; ++i) 66 { 67 int x = read(); 68 merge(i, x); 69 } 70 write(ans), enter; 71 return 0; 72 }
View Code

[NOIP2015] 信息傳遞