食物鏈

小码king發表於2024-10-18

食物鏈

動物王國中有三類動物 A,B,C這三類動物的食物鏈構成了有趣的環形。

A 吃 B,B 吃 C,C 吃 A。

現有 N 個動物,以 1∼N 編號。

每個動物都是 A,B,C 中的一種,但是我們並不知道它到底是哪一種。

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

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

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

此人對 N 個動物,用上述兩種說法,一句接一句地說出 KK 句話,這 KK 句話有的是真的,有的是假的。

當一句話滿足下列三條之一時,這句話就是假話,否則就是真話。

  1. 當前的話與前面的某些真的話衝突,就是假話;
  2. 當前的話中 X 或 Y 比 N 大,就是假話;
  3. 當前的話表示 X 吃 X,就是假話。

你的任務是根據給定的 N 和 K 句話,輸出假話的總數。

輸入格式

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

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

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

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

輸出格式

只有一個整數,表示假話的數目。

資料範圍

1≤N≤50000
0≤K≤100000

輸入樣例:

100 7
1 101 1 
2 1 2
2 2 3 
2 3 3 
1 1 3 
2 3 1 
1 5 5

輸出樣例:

3

AC程式碼:

#include <iostream>
using namespace std;
const int Mn=50010;
//p[i]表示第i個節點的父節點,d[i]表示各個節點的距離;(自理解)
int p[Mn],d[Mn];

//程式碼核心,遞迴查詢父節點+路徑壓縮;
int find(int 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=0;i<n;i++){
        p[i]=i;
        d[i]=0;
    }
    int res=0;   //記錄假話數量;
    while(m--){
        int c,x,y;
        cin >> c >> x >> y;
        //判斷當前的話中X或Y比N大,就是假話;
        if(x>n || y>n) res++;
        else{
            int l=find(x),k=find(y);
            //若c=1,則表示X和Y是同類。
            if(c==1){
                //合併的情況
                if(l==k && (d[x]-d[y])%3) res++;
                else if(l!=k){
                    p[l]=p[k];
                    d[l]=d[y]-d[x];
                }
            }else{
                //合併情況;
                //這裡為什麼要減一呢?因為是x吃y,如果在節點小一的情況下,能匹配為同類,則說明x就是吃y對的;
                if(l==k && (d[x]-d[y]-1)%3) res++;
                else if(l!=k){
                    p[l]=p[k];
                    d[l]=d[y]-d[x]+1;
                }
            }
        }
    }
    cout << res << endl;
    return 0;
}

大概構圖思想:


核心程式碼遞迴操作:

int find(int x){
    if(p[x]!=x){
        int t=find(p[x]);
        //路徑壓縮:記錄子節點到祖先節點距離;實現類似直接讓當前節點直接指向祖先接節點;
        d[x]+=d[p[x]];
        //更新父節點:這個建議手推遞迴,就可以很清楚了;
        p[x]=t;  
    }
    return p[x];
}

相關文章