深度探索C++物件模型讀書筆記
阿新 • • 發佈:2020-12-02
並查集
並查集樸素實現:
inline ll find(ll x)
{
if(fa[x]==x) return x;
return find(fa[x]);
}
路徑壓縮
inline ll find(ll x)
{
if(fa[x]==x) return x;
return fa[x]=find(fa[x]);
}
在樸素實現的過程中,複雜度較高,而路徑壓縮的複雜度為 \(O(α(n))\) ,可近似認為其複雜度為常數級別
但是路徑壓縮的做法是把所有的子節點都直接與根節點相連,會破壞樹的原始結構
拓展域
對於多種關係的處理,我們可以將其合併範圍增大,以表示不同的合併關係
- 例:食物鏈
將 \(1\) ~ \(n\) 範圍表示A類,\(n+1\) ~ \(2n\) 範圍表示B類,\(2n+1\) ~ \(3n\) 範圍表示C類
之後按照題目的食物鏈關係合併即可
code
#include<iostream> #include<cstdio> #include<math.h> #include<cstring> #include<algorithm> #define ll long long const ll maxn=5e4+10; ll fa[3*maxn]; ll n,k,a,b,ans; inline ll find(ll x) { if(fa[x]==x) return x; else return fa[x]=find(fa[x]); } int main(void) { scanf("%lld %lld",&n,&k); for(int i=1;i<=n*3;i++) fa[i]=i; for(int i=1;i<=k;i++) { ll op,x,y; scanf("%lld %lld %lld",&op,&x,&y); if(x>n||y>n) { ans++; continue; } if(op==1) { if(find(x+n)==find(y)||find(x+n+n)==find(y)) ans++; else { fa[find(x)]=find(y);//同類 fa[find(x+n)]=find(y+n);//同類 fa[find(x+n+n)]=find(y+n+n);//同類 } } if(op==2) { if(x==y) { ans++; continue; } if(find(x)==find(y)||find(x)==find(y+n+n)) ans++; else { fa[find(x+n)]=find(y+n+n);//B->C fa[find(x)]=find(y+n);//A->B fa[find(x+n+n)]=find(y);//C->A } } } printf("%lld\n",ans); return 0; }
邊帶權
即在路徑壓縮的基礎上,在進行合併之前,先對邊權進行一些處理,之後再進行合併的操作
- 例:銀河英雄傳說
code
#include<iostream> #include<cstdio> #include<cstring> #include<cstdlib> #include<algorithm> #include<math.h> #include<vector> #include<queue> #define ll long long using namespace std; const ll maxn=3e4+10; ll t,x,y; char op; ll fa[maxn],dis[maxn],siz[maxn]; inline ll find(ll x) { if(fa[x]==x) return x; ll rot=find(fa[x]); dis[x]+=dis[fa[x]]; return fa[x]=rot; } inline void upd(ll x,ll y) { ll ex=find(x),ey=find(y); fa[ex]=ey; dis[ex]=siz[ey]; siz[ey]+=siz[ex]; } int main(void) { ios_base::sync_with_stdio(0); cin.tie(0); cout.tie(0); for(int i=1;i<=maxn;i++) fa[i]=i,siz[i]=1; memset(dis,0,sizeof(dis)); cin>>t; while(t--) { cin>>op>>x>>y; if(op=='M') { upd(x,y); } if(op=='C') { ll ex=find(x),ey=find(y); if(ex!=ey) { cout<<"-1"<<'\n'; continue; } else { if(x==y) { cout<<"0"<<'\n'; continue; } cout<<abs(dis[x]-dis[y])-1<<'\n'; } } } return 0; }