第三部分 數據結構 -- 第四章 圖論算法1390:食物鏈【NOI2001】

1390:食物鏈【NOI2001】

時間限制: 1000 ms 內存限制: 65536 KB
提交數: 1806 通過數: 906
【題目描述】
動物王國中有三類動物A,B,C,這三類動物的食物鏈構成了有趣的環形。A吃B, B吃C,C吃A。

現有N個動物,以1-N編號。每個動物都是A,B,C中的一種,但是我們並不知道它到底是哪一種。

有人用兩種說法對這N個動物所構成的食物鏈關係進行描述:

第一種說法是"1 X Y",表示X和Y是同類。

第二種說法是"2 X Y",表示X吃Y。

此人對N個動物,用上述兩種說法,一句接一句地說出K句話,這K句話有的是真的,有的是假的。當一句話滿足下列三條之一時,這句話就是假話,否則就是真話。

1)當前的話與前面的某些真的話衝突,就是假話;

2)當前的話中X或Y比N大,就是假話;

3)當前的話表示X吃X,就是假話。

你的任務是根據給定的N(1≤ N ≤50,000)和K句話(0≤K≤100,000),輸出假話的總數。

【輸入】
第一行是兩個整數N和K,以一個空格分隔。

以下K行每行是三個正整數 D,X,Y,兩數之間用一個空格隔開,其中D表示說法的種類。

若D=1,則表示X和Y是同類。

若D=2,則表示X吃Y。

【輸出】
只有一個整數,表示假話的數目。

【輸入樣例】
100 7
1 101 1
2 1 2
2 2 3
2 3 3
1 1 3
2 3 1
1 5 5
【輸出樣例】
3
【提示】
【樣例解釋】

100122212171011231351233315假話真話真話假話假話真話真話


思路:這裏我們維護每個結點到其父親的距離來表示與父親的關係,0代表是同類,1是吃父親,2是被父親吃。
因爲吃與被吃的關係構成了環,所以將距離累加再對3取模就可以得到結點與其他結點的關係了,若給出的X和Y不在同一並查集內,需要合併,讓一方的最終祖先指向另一方的最終祖先,就需要根據給定的關係以及兩結點到其祖先的距離求出兩個祖先間該有的距離;若給定的X和Y已經在同一並查集內,根據他們到祖先的距離求出他們的距離判斷即可。
0 吃1 1吃 2 2 吃0
(0-1)+3 =2 (1-2)+3 =2,2-0 = 2;
c = (c - dist[a] + dist[b] + 3) % 3; 表示 x吃y

	 #include <cstdio>
	 #include<cstring>
	 using namespace std;
	 
	  inline int get_num() {
	      int num = 0;
	      char c = getchar();
	      while (c < '0' || c > '9') c = getchar();
	      while (c >= '0' && c <= '9')
	          num = num * 10 + c - '0', c = getchar();
	      return num;
	 }
	 
	 const int maxn = 5e4 + 5;
	 
	 int fa[maxn], dist[maxn];
	 
     int find(int i) {
	     if (i == fa[i]) return i;
	     int g = fa[i];
	     fa[i] = find(g);
	     dist[i] = (dist[i] + dist[g]) % 3;
	     return fa[i];
	 }
	 
	 inline void un(int a, int b, int c) {
	     c = (c - dist[a] + dist[b] + 3) % 3;
	     a = find(a), b = find(b);
	     fa[a] = b, dist[a] = c;
	 }
	 
	 int main() {
	     int n, k, ans = 0;
	     n = get_num(), k = get_num();
	     for (int i = 1; i <= n; ++i)
	         fa[i] = i, dist[i] = 0; //初始化
	         //與父親的距離爲0是同類,1是吃父親,2是被吃
	     int c, x, y;
	     for (int i = 1; i <= k; ++i) {
	         c = get_num(), x = get_num(), y = get_num();
	         if (x > n || y > n) ++ans;
	         else if (c == 2 && x == y) ++ans;
	         else {
	             if (find(x) != find(y)) un(x, y, c - 1);
	             else if ((dist[x] - dist[y] + 3) % 3 != c - 1) ++ans;
	         }
	     }
	     printf("%d", ans);
	    return 0;
	 }
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章