加權並查集
阿新 • • 發佈:2017-09-22
void print 食物鏈 lag 遍歷 並查集 read 否則 忽略
加權並查集是一種特殊的並查集,除可提供查詢操作外,還可用於表示元素與其代表元素的關系。下面以食物鏈為例,講解一下加權並查集。
#include<cstdio> //調用cstdio庫,使用getchar函數 #include<cctype> //調用cctype庫,使用isdigit函數,返回參數是否為整數 int N,K,ans,r,x,y; //定義變量用於有幾個動物,幾句話,答案,以及動物的關系和兩個要描述的動物 int f[50005],d[50005]; //定義數組記錄代表元素,以及到達代表元素的距離 inline int get_num() { //內聯get_num函數,讀入整數 int num = 0; //定義整型變量num,並賦值為0 char c; //定義字符型變量c bool flag = false; //定義布爾值變量flag,並置為假 while ((c = getchar()) == ‘ ‘ || c == ‘\n‘ || c == ‘\r‘); //忽略開頭的空格,換行符及回車符 if (c == ‘-‘) flag = true; //如果讀到負號,就將負數標誌置為真 else num = c - ‘0‘; //否則將讀到的第一個數字保存; while (isdigit(c = getchar())) //只要讀入的還是數字,就循環 num = num * 10 + c - ‘0‘; //將num整體前移一位,並將新讀入的一位數字保存 return (flag ? -1 : 1) * num; //返回讀到的整數,若負數標誌為真,就返回其相反數,即一個負數 } int find(int i) { //定義函數查詢代表元素以及到達代表元素的距離 if(i==f[i]) return i; //找到代表元素返回 int oldf=f[i]; //記錄下元素之前的代表元素 f[i]=find(f[i]); //更新元素的代表元素 d[i]=(d[i]+d[oldf])%3; //更新元素與代表元素的距離 return f[i]; //返回代表元素 } void check(int r,int x,int y) { //定義函數檢查是否為假話 if(x>N||y>N) {++ans;return;} //若動物編號超出範圍,則為假話 if(r==2&&x==y) {++ans;return;} //若說動物自己吃自己,則為假話 if(find(x)==find(y)) { //若兩個動物在同一集合中 if((d[x]-d[y]+3)%3!=r-1) ++ans;return; //動物之間的距離不符合描述,則為假話 } else { d[f[x]]=(3-d[x])%3; //求出代表元素到該元素的距離 f[f[x]]=x;f[x]=y; //讓代表元素指向該元素,即該元素成為代表元素,並指向y d[f[y]]=(3-d[y])%3; //同上 f[f[y]]=y;f[y]=y;d[y]=0; // 同上,並讓y成為代表元素,令其到代表元素的距離為0 if(r==1) d[x]=0; //若為同類,則x到y距離為0 else d[x]=1; //若x吃y,則x到y距離為1 /* 另一種合並方法 f[f[y]]=f[x]; //讓y的代表元素指向x的代表元素 d[f[y]]=(d[x]-d[y]-(r-1)+3)%3; //更新y的代表元素到其代表元素的距離 */ } } int main() { N=read();K=read(); //讀入N,K for(int t=1;t<=N;++t) f[t]=t; //初始化每個元素的代表元素 for(int t=1;t<=K;++t) { //遍歷每句話 r=read();x=read();y=read(); //讀入r,x,y check(r,x,y); //調用check函數 } printf("%d",ans); //打印答案 return 0; }
加權並查集