***POJ 1182 食物鏈

原題鏈接

Description
動物王國中有三類動物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),輸出假話的總數。

Input
第一行是兩個整數N和K,以一個空格分隔。
以下K行每行是三個正整數 D,X,Y,兩數之間用一個空格隔開,其中D表示說法的種類。
若D=1,則表示X和Y是同類。
若D=2,則表示X喫Y。
Output
只有一個整數,表示假話的數目。

Sample Input
100 7
1 101 1
2 1 2
2 2 3
2 3 3
1 1 3
2 3 1
1 5 5

Sample Output
3

思路:並查集。x,x+N,x+2N分別是編號x的動物爲A/B/C類的可能性。每給出一句話,將同時成立的可能性加入一個並查集,判斷是否矛盾。

AC代碼:

#include <iostream>
#include <stdio.h> 
#include <algorithm>
#include <cstdlib>
#define N 50000  //最多50000個動物 
using namespace std;

int i,n,k;  //n個動物,k句話 
int x,y;
int par[3*N];  //父親
int rank[3*N];  //樹高

//並查集 

int find(int x)  //找根
{
    if(par[x]==x) return x;
    else return par[x]=find(par[x]);
 } 

bool same(int x0,int y0)  //是否同集
{
    return find(x0)==find(y0);
} 


void unite(int x,int y)
{
    x=find(x);
    y=find(y);
    if(x==y) return;
    else{
        if(rank[x]>rank[y])  par[y]=x;
        else{
            par[x]=y;
            if(rank[x]==rank[y])  rank[y]++;
        }
    }
}

int main()
{
    int d,ans=0;  //d:1或2 
    for(i=0;i<N*3;i++)  //x,x+N,x+N*2是x分別屬於A,B,C組的可能性 
    {
        par[i]=i;
        rank[i]=0;
    }
    scanf("%d %d",&n,&k);
    getchar(); 
    for(i=0;i<k;i++){
        scanf("%d %d %d",&d,&x,&y);
        getchar(); 
        x=x-1,y=y-1;
        if(x<0 || y<0 || x>=n || y>=n){
            ans++;
            continue;
        }
        if(d==1){
            if(same(x,y+N) || same(x,y+N*2)){
                ans++;
                continue;
            }
            else{
                unite(x,y);  //x屬於A組和y屬於A組會同時發生或同時不發生 
                unite(x+N,y+N);
                unite(x+N*2,y+N*2);
            }
        }
        if(d==2){
            if(same(x,y) || same(x,y+N*2)){
                ans++;
                continue;
            }
            else{
                unite(x,y+N);
                unite(x+N,y+N*2);
                unite(x+N*2,y);
            }
        }
    } 
    cout<<ans<<endl;
    return 0;
}
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章