題目來源:[NWPU][2014][TRN][12]並查集 C 題
http://vjudge.net/contest/view.action?cid=50731#problem/C
作者:npufz
題目:
Description
現有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
以下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
代碼:
#include <iostream>
#include <cstdio>
#include <cstring>
#include <cstdlib>
using namespace std;
int parent[50003];
int real[50003],n;
int getparent(int a)
{
if(a==parent[a])
return a;
int t;
t=getparent(parent[a]);
real[a]=(real[parent[a]]+real[a])%3;
//cout<<real[a]<<endl;
parent[a]=t;
return parent[a];
}
bool panduan (int d,int dw1,int dw2)
{
int pre1,pre2;
if(dw1>n||dw2>n||dw1<1||dw2<1||d>2||d<1) return false ;
if(d==2&&dw1==dw2) return false;
if(d==1&&dw1==dw2) return true;
pre1=getparent(dw1);
pre2=getparent(dw2);
if(d==1)
{
if(dw1==dw2) return true;
if(dw1!=dw2)
{
if(pre1==pre2)
{
if(real[dw1]==real[dw2]) return true;
return false;
}
if(pre1!=pre2)
{
if(real[dw1]>=real[dw2])
{
parent[pre2]=pre1;
real[pre2]=(real[dw1]-real[dw2]);
return true;
}
else
{
parent[pre1]=pre2;
real[pre1]=(real[dw2]-real[dw1]);
return true;
}
}
}
}
if(d==2)
{
if(pre1==pre2)
{
if((real[dw2]-real[dw1])==1) return true;
if((real[dw1]-real[dw2]==2)) return true;
return false ;
}
if(pre1!=pre2)
{
if(real[dw1]==real[dw2])
{
parent[pre2]=pre1;
real[pre2]=1;
return true;
}
if((real[dw1]+1)>=real[dw2])
{
//cout<<"ok"<<real[pre2]<<endl;
parent[pre2]=pre1;
real[pre2]=((real[dw1]+1)-real[dw2])%3;
//cout<<"ok"<<real[pre2]<<endl;
return true;
}
if((real[dw1]+1)<real[dw2])
{ //cout<<"not ok"<<real[pre2];
parent[pre2]=pre1;
real[pre2]=2;
//cout<<"not ok"<<real[pre2];
return true;
}
}
}
return true;
}
int main()
{
int k,d,dw1,dw2,wrong;
scanf("%d%d",&n,&k);
for(int i=1;i<=n;i++)
{
real[i]=0;
parent[i]=i;
}
wrong=0;
for(int i=0;i<k;i++)
{
scanf("%d%d%d",&d,&dw1,&dw2);
if(!panduan(d,dw1,dw2))
wrong++;
}
printf("%d\n",wrong);
return 0;
}
反思:並查集在於把元素的分類和關係的描述上進行合理的數據維護,用壓縮路徑或者是RANK值使複雜度控制在LOG N 以下,具體的實現形式不拘一格,在這一題中,我把動 物之間已知的關係構造出一顆顆的樹,也就是森林,當兩棵樹的元素有關係時,就把一棵樹的樹根連到另一棵樹根上,在每次進行對樹根的查找時,就直接把這個葉子節 點連接到根節點上,並同時確定它和根節點的關係,一開始由於第81行的那個是2的值寫成了1,就WA了,還以爲整個數據集合的處理有問題,就糾結了一個晚上也沒有
找出錯誤,後來找到就A了