食物鏈(並查集)
阿新 • • 發佈:2021-08-02
題目
動物王國中有三類動物 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 句話有的是真的,有的是假的。
當一句話滿足下列三條之一時,這句話就是假話,否則就是真話。
當前的話與前面的某些真的話衝突,就是假話;
當前的話中 X 或 Y 比 N 大,就是假話;
當前的話表示 X 吃 X,就是假話。
你的任務是根據給定的 N 和 K 句話,輸出假話的總數。
輸入輸出
輸入:第一行是兩個整數 N 和 K,以一個空格分隔。
以下 K 行每行是三個正整數 D,X,Y,兩數之間用一個空格隔開,其中 D 表示說法的種類。
若 D=1,則表示 X 和 Y 是同類。
若 D=2,則表示 X 吃 Y。
輸出:只有一個整數,表示假話的數目。
思路
三種被吃關係構成一個環,可以用並查集來維護每個點到根節點的距離。
距離模3餘0表示與根節點是同類,距離模3餘1表示被根節點吃的一類,距離模3餘2表示吃根節點的一類。
作者:inss!w! 出處:https://www.cnblogs.com/Hfolsvh/ 版權宣告:本部落格所有文章除特別宣告外,均採用 BY-NC-SA 許可協議。轉載請註明出處!#include <iostream> #include <cstring> #include <algorithm> using namespace std; const int N = 50010; int p[N],d[N]; //d[i]一開始存的是i到父節點的距離,最後存的是第i個點到根節點的距離 int find(int x){ //路徑壓縮 + x到根節點的距離 if(p[x] != x){ int t = find(p[x]); d[x] += d[p[x]]; p[x] = t; } return p[x]; } int main() { int n,m; cin >> n >> m; for (int i = 1; i <= n; i ++ ) p[i] = i; int res = 0; //假話的數量 while (m -- ){ int c; //每次說法的種類 int x,y; cin >> c >> x >> y; if(x > n || y > n) res ++; else{ int px = find(x), py = find(y); //記錄x和y的根節點 if(c == 1){ //x和y是同類 if(px == py && (d[x] - d[y]) % 3){ //x和y屬於一個集合中了,但是模3的結果不同,就是假話 res ++; } else if(px != py){ //x和y不屬於一個集合,就把x併到y的集合 p[px] = py; d[px] = d[y] - d[x]; } } else{ //x吃y,x模3比y模3大1 if(px == py && (d[x] - d[y] - 1) % 3) res ++; //在一個集合中,但不滿足x吃y關係 else if(px != py){ //不在一個集合中 p[px] = py; d[px] = d[y] - d[x] + 1; } } } } cout << res; return 0; }