並查集-A Bug's Life(poj2492)
阿新 • • 發佈:2018-12-09
題意:
給出N條蟲子,讓a和b交配,
給出M對a和b交配後問,
有沒有性別矛盾的蟲子,
即和一隻蟲子和男的交配完之後又和女的交配
題解:
1.壓縮路徑關係轉化,r[x] = (r[x]+r[f[x]])%2,很好理解//r[x]表示x和fx的關係,0同性,1異性
若x和fx為同性(r[x] = 0):
fx和ffx為異性(r[fx] = 1),則x和ffx為異性,x和ffx的關係r[x]更新為0+1=1
fx和ffx為同性(r[fx] = 0),則x和ffx為同性,x和ffx的關係r[x]更新為0+0=0
若x和fx為異性(r[x] = 1):
fx和ffx為異性(r[fx] = 1),則x和ffx為同性,x和ffx的關係r[x]更新為(1+1)%2=0
fx和ffx為同性(r[fx] = 0),則x和ffx為異性,x和ffx的關係r[x]更新為1+0=1
2.並查集聯合若父節點相同
if(r[x] == r[y]) mark = true; //x和y性別不同,因為父節點相同,所以x,y和父節點關係相同就是假話
3.並查集聯合若父節點不同,這句話為真話,把fy的父節點設定為fx
f[fy] = fx;
r[fy] = (1+r[x]-r[y])%2;
#include <iostream> #include <cstdio> #include <cstring> using namespace std; int f[2010], r[2010];//f陣列指向與它交配的bug,初始化自交 //r表示他的父節點與它是同性還是異性,0同性,1異性 bool mark; int find_head(int x) { int fx = x; if(x != f[x]) { fx = find_head(f[x]); r[x] = (r[x]+r[f[x]])%2; f[x] = fx; } return fx; } void union_set(int x, int y) { int fx = find_head(x); int fy = find_head(y); if(fx == fy)//父親結點相同 { if(r[x] == r[y]) //x和y性別不同,因為父節點相同,所以x,y和父節點關係相同就是假話 { mark = true; } } else//父親結點不同,這句話為真話,把fy的父節點設定為fx { f[fy] = fx; r[fy] = (1+r[x]-r[y])%2; } } int main() { int t; cin>>t; for(int i = 1; i <= t; i++) { int n, m; mark = false; scanf("%d%d", &n,&m); memset(r, 0, sizeof(r)); for(int k = 1; k <= 2010; k++) { f[k] = k; } for(int j = 1; j <= m; j++) { int x, y; scanf("%d%d", &x,&y); if(!mark) { union_set(x, y); } } cout<<"Scenario #"<<i<<":"<<endl; if(mark) cout<<"Suspicious bugs found!"<<endl; else cout<<"No suspicious bugs found!"<<endl; cout<<endl; } }