[NOI2001]食物鏈


 洛谷原題鏈接

這是一道分類並查集的題目。

我們要根據題目的要求,求出謊話的數目。題目給了我們一些明確的判斷標准:

但是我們會發現,如果只按照這三個條件和普通的並查集,我們只能得30分。

30分做法:我們可以用普通並查集和一個表示誰是誰的食物的數組來完成。

30分代碼:

#include<bits/stdc++.h>
#define R register int
#define M 500500
using namespace std;
int n,k,fa[M],ans,eat[M];
inline int find(int x){return fa[x]= fa[x]==x ? x : find(fa[x]);}
int main(){
    ios::sync_with_stdio(0);
    int q,x,y;
    cin>>n>>k;
    for(R i=1;i<=n;++i) fa[i]=i;
    for(R i=1;i<=k;++i){
        cin>>q>>x>>y;
        if(x>n || y>n)    ++ans;
        else if(q==1){
            if(eat[x]==y || eat[y]==x) ++ans;
            else if(find(x)!=find(y)) fa[find(x)]=find(y);
        }
        else{
            if(x==y || eat[y]==x || find(x)==find(y) || eat[x]!=0) ++ans;
            else eat[x]=y;
        }
    }
    printf("%d",ans);
    return 0;
}

滿分做法:

當我們再次仔細讀題,就會發現,題目中是有幾條隱含在題意里面的判斷條件的。

從這里我們可以看出一共只有3種動物,而且食物鏈是一個環。那么我們就可以得出這樣一條關系:如果x的食物是y,那么y的天敵是x,x的天敵是y的食物。這樣的話很顯然,一個數組是無法完成判斷的。而且我們並不知道,x和y分別是哪一種動物。

這時候我們就可以用種類並查集來實現這道題。種類並查集可以用來處理維護一些對立的關系,比如:敵人的敵人是朋友。我們通常會把並查集數組擴大n倍,n就是種類。所以這道題我們就可以開三倍的並查集數組,1到n表示種類A,n+1到n*2表示種類B,n*2+1到n*3表示種類C。然后我們就可以在合並的過程中維護各個點的信息了。

還有部分解釋在寫在代碼注釋里了哦↓ ↓ ↓ ↓ ↓ ↓ ↓

滿分代碼:

#include<bits/stdc++.h>
#define R register int
#define M 500500
using namespace std;
int n,k,fa[M],ans; //n表示同類  n+n表示食物  n+n+n表示天敵 
inline int find(int x){return fa[x]= fa[x]==x ? x : find(fa[x]);}
inline void unity(int x,int y){fa[find(x)]=find(y);} 
int main(){
    ios::sync_with_stdio(0);
    int q,x,y;
    cin>>n>>k;
    for(R i=1;i<=n*3;++i) fa[i]=i;
    for(R i=1;i<=k;++i){
        cin>>q>>x>>y;
        if(x>n || y>n)    ++ans;
        else if(q==1){
            if(find(x+n)==find(y) || find(x+(n<<1))==find(y)) ++ans;
            //判斷x是y的同類是假話:y是x的食物 , y是x的天敵 
            else unity(x,y),unity(x+n,y+n),unity(x+(n<<1),y+(n<<1));
            //如果x和y是同一個種類:那么x和y是同一種類,x和y的食物是同一種類,x和y的天敵是同一種類 
        }
        else{
            if(x==y || find(x)==find(y) || find(x)==find(y+n)) ++ans;
            //判斷x吃y是假話:x能吃x(題目要求),x和y是同類的,x是y的食物 
            else unity(x,y+(n<<1)),unity(x+n,y),unity(x+(n<<1),y+n);
            //如果x吃y:y的天敵是x,y是x的食物,x的天敵是y的食物(因為一共只有三種動物,而且食物鏈是一個環形的,不理解的看一下代碼后面的圖片) 
        }
    }
    printf("%d",ans);
    return 0;
}


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM