POJ 1703 Find them, Catch them 种类并查集
題意
給出一堆點和關系
D為兩點不同集合
A為查詢兩點是否不同集合
n<=1e5
code
#include<cstdio> #include<iostream> #include<algorithm>using namespace std; const int maxn = 1e5+7; int f[maxn],rel[maxn];//rel為0表示與父節點不同類 1為同類 int find(int x){int t;if(f[x]==x)return x;t = find(f[x]);rel[x] = (rel[x]+rel[f[x]]+1)%2;//當前節點與舊父節點之間的關系、父節點與根節點的關系 可以判斷出 當前節點和根節點的關系 即所謂的關系運算 模擬現實中的關系判斷 return f[x] = t;//如果這里面總是保存的與父節點的關系 我們沒法通過兩個不同的節點判斷他倆的關系 但我們如果知道兩個不同的節點與根節點的關系 就可以判斷兩個節點之間的關系 }//當我們需要判斷兩個點的關系時 我們需要知道兩個節點對一個相同的節點的關系 才能判斷出當前兩個節點的關系 int main() {int t;scanf("%d",&t);while(t--){int n,m;scanf("%d%d",&n,&m);for(int i=1;i<=n;i++)f[i] = i,rel[i] = 1;while(m--){char o[4];int a,b;scanf("%s%d%d",o,&a,&b);int fa = find(a);int fb = find(b);if(o[0]=='A'){if(fa==fb){if(rel[a]==rel[b])puts("In the same gang.");else puts("In different gangs.");//與根節點關系不同 那么一定不同集 } else puts("Not sure yet.");}else {//只要有關系 就給他們連到一起 不管什么關系 我們都可以用rel數組記錄他們分別于根節點的關系 那么我們如何判斷這兩個點的關系 就可以通過他們分別對根節點的關系來做出來 f[fa] = fb;rel[fa] = (rel[a]+rel[b])%2;}}}return 0; }分析
種類并查集
當我們判斷兩個點的關系時 我們如何判斷呢
基礎的并查集知識告訴我們 我們可以判斷這兩個點是否在一個聯通塊中 這兩個點是否是一個集合
現在關系復雜了 兩個元素可以是一個集合的也可以是不同集合的 我們如何判斷呢
假設我們記錄下每個節點與父節點的關系
那么當我們查詢兩個節點時
我們都知道他們與父節點的關系
我們也知道他們的根節點是誰
if 兩個節點是不同集合的 那么我們如何判斷出來呢
僅憑兩個父節點貌似不好判斷
假如每一個關系都建立一個獨立的樹
由于數據并不是按照相同關系給我們的
而是按照不同或相同關系給我們的
那么我們就需要遞推兩個元素的關系
假如 a-b不同 b-c不同 那么a-c相同 我們需要判斷出來
這里就需要種類并查集來做
假如當我們查詢 ac的關系的時候 如果我們都知道 a和c與另外一個節點的關系
那么我們就能判斷出來ac的關系 通過兩個變量與共同的第三方變量的關系
于是種類并查集規定
我們維護每個點和父節點的關系 但最終我們實質維護的是每個節點與 根節點的關系!
假如所有出現的兩個點都在一棵樹里 沒出現的點 我們不必管
我們只需要去維護每個點與根節點的關系 我們就可以推出兩個節點的相互關系
如何實現這個關系 就是利用關系數量取余操作
因為這里的關系 并不是每個集合一個獨立的樹 獨立的樹 我們無法判斷交叉關系假如 a在一個樹上 b在另一顆樹上 那么c如何連到與b不同的那棵樹呢?可以維護兩個集合 只不過有些時候我們的關系不止是兩層 有時關系會變成多層 那么就不好維護兩個集合了
話說種類并查集有沒有迭代的寫法?
創作挑戰賽新人創作獎勵來咯,堅持創作打卡瓜分現金大獎總結
以上是生活随笔為你收集整理的POJ 1703 Find them, Catch them 种类并查集的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: 分享几个免费的开源邮件服务器软件
- 下一篇: cad刷新快捷键_47个快捷键、50个C