Spring-boot整合pg、mongo多資料來源過程詳解
阿新 • • 發佈:2020-11-19
並查集就是給你一個圖,裡面有很多點,並就是把點合併一個集合,把a點搞為b點父親;查就是查點在哪個集合,查a點的父親祖先是誰。
初始化點的父親是自己
int Find(int x){ if(father[x] != x)//如果父親不是自己,那就遞迴找父親 father[x] = Find(father[x]);//找他父親時把其兒子也連上,大多數這樣壓縮下就行,也可以寫Find(father[x])但沒壓縮 return father[x];//找到父親返回他 } //查詢遞迴棧爆了的話用迭代 int Find(int x){ int y = x; while(father[y] != y){ y = father[y];//把原x的爸爸賦值給y,再回檢查y的爸爸是否等於y } //壓縮,爸爸直接一步到位 int p = x, j; while(p != y){//就是把從x的父親的父親的...的父親(如果有)全部直接一步到祖先, j = father[p];//不用一步步找 father[p] = y; p = j; } return y; } void Union(int x, int y){ int p = Find(x);//找x父親 intq = Find(y);//找y父親 if(p != q){ father[x] = y;//如果不是同一個父親, //那就把y作為x父親,father[y]=x也可以 } } //啟發式合併優化,加個Rank陣列初始化為0,存他查詢的深度,把深度小掛在大的上 void Union(int x, int y, int Rank[]){ int p = Find(x); int q = Find(y); if(p != q){ if(Rank[p] < Rank[q]){ father[p]= q;//這樣就不會加深度 } else if(Rank[p] > Rank[q]){ father[q] = p;//同上 } else{ father[q] = p;//隨便搞個父親,父親深度加1 Rank[p]++; } } }
例:Luogu P1525並查集時區分敵友
#include<bits/stdc++.h> using namespace std; typedef long long ll; const int maxn = 2e5 + 5; ll n, m, k, sum; string s; priority_queue<int, vector<int>, greater<int> >q; struct node{ int x, y, z;//z為怨氣值 }a[maxn]; int f[maxn], b[maxn]; void initialise(){//f初始化,各自在自己監獄 for(int i = 0; i < maxn; i++){ f[i] = i; } } int Find(int x){ if(f[x] != x){ f[x] = Find(f[x]); } return f[x]; } bool cmp(node a, node b){//sort排序 return a.z > b.z; } void Union(int x, int y){ int p = Find(x); int q = Find(y); if(p != q){ f[p] = q; } } int main(){ //ios_base::sync_with_stdio(0); //cin.tie(); cout.tie(); cin>>n>>m; initialise(); for(int i = 1; i <= m; i++) cin>>a[i].x>>a[i].y>>a[i].z; sort(a + 1, a + m + 1, cmp);//按他怨氣值大小排序,大的在前 for(int i = 1; i <= m; i++){ int p = Find(a[i].x); int q = Find(a[i].y); if(p == q){//如果同個監獄,直接輸出怨氣值,因為排了序 cout<<a[i].z; return 0; } //如果a[i].x沒有敵人,把a[i].y設為他敵人互為敵人不能關一起 if(!b[a[i].x]){ b[a[i].x] = a[i].y; } else{//a[i].x有敵人(就是b[a[i].x]),把他敵人和a[i].y關一起,這樣關一起的怨氣值肯定沒和原先高,因為排了序 Union(b[a[i].x], a[i].y); } if(!b[a[i].y]){//同上 b[a[i].y] = a[i].x; } else{//同上 Union(b[a[i].y], a[i].x); } } cout<<0; return 0; }
例:Luogu P2024同上題,不過是3個類
#include<bits/stdc++.h> using namespace std; typedef long long ll; const int maxn = 3e5 + 5; int n, m, k, sum; string s; queue<int> q; int f[maxn];//一倍存自己,兩倍存朋友,三倍存敵人,在這一倍是A類,2倍是B類,3倍是C類 //各自倍的如果是同集合,說明相互是敵人;同倍的在同一集合,說明是自己人 void initialise(){ for(int i = 0; i < maxn; i++){ f[i] = i; } } int Find(int x){ if(f[x] != x){ f[x] = Find(f[x]); } return f[x]; } void Union(int x, int y){ int p = Find(x); int q = Find(y); if(p != q){ f[p] = q;//這是p吃q的意思,也可以f[q]=p,看指向爸爸是哪種意思 } } int main(){ //ios_base::sync_with_stdio(0); //cin.tie(); cout.tie(); initialise(); cin>>n>>m; int x, y, z; for(int i = 1; i <= m; i++){ cin>>z>>x>>y; if(x > n || y > n){//依題意,假話 sum++;continue; } if(z == 1){//同類的話,找一倍的x和在2倍的y,和一倍x和三倍y是不是同集合,同集合那就不是同類 if(Find(x) == Find(y + n) || Find(x) == Find(y + n + n)){ sum++;continue; } //不符合上面的情況說明是真話,那把各自同倍(也就是各自類)的合併一起 Union(x, y); Union(x + n, y + n); Union(x + n + n, y + n + n); } else if(z == 2){//x吃y,那判斷下同倍xy在不在同集合,是的話就假話;還判斷是不是y吃x,找三倍y和一倍x在不在同集合,在就是y吃x if(Find(x) == Find(y) || Find(x) == Find(y + n + n)){ sum++;continue; } //不符合上面的話代表是真話 Union(x + n + n, y);//C類x吃A類的y(也就是三倍的x吃一倍的y) Union(x, y + n);//A類x吃B類y(也就是一倍的x吃二倍的y) Union(x + n, y + n + n);//B類x吃C(也就是二倍的x吃三倍的y) } } cout<<sum; return 0; }
例:Luogu P1196並查集時兼顧維護
#include<bits/stdc++.h> using namespace std; typedef long long ll; const int maxn = 3e4 + 5; ll n, m, k, sum; string s, r; int num[maxn], dis[maxn], f[maxn]; //num是是該數字在組的成員數量,dis是該數離他組組頭的距離 int Find(int x){ if(f[x] != x){ int r = f[x]; f[x] = Find(f[x]); dis[x] += dis[r];//如果x有父親,就是和他父親在同列,那x到隊頭的距離也就變長了此時dis[x]只代表到他父親距離,要加上他父親到隊頭距離 num[x] = num[f[x]];//x所在列的數量也就是他父親所在列的數量 } return f[x]; } void Union(int x, int y){ int p = Find(x); int q = Find(y); if(p != q){ f[p] = q;//p父親是q,p所在列移動到q所在列 dis[p] = dis[q] + num[q];//合併要移動列,p到隊頭距離增加到原q到隊頭距離加上q所在列的原成員數量 num[q] += num[p];//q所在列數量要加上p所在列數量 num[p] = num[q];//p所在列的數量和他父親所在列數量一樣 } } void query(int x, int y){ int q = Find(x); int p = Find(y); if(q != p){ cout<<-1<<endl; } else{//輸出他倆之間距離,記著要減一 cout<<abs(dis[x] - dis[y]) - 1<<endl; } } int main(){ //ios_base::sync_with_stdio(0); //cin.tie(); cout.tie(); for(int i = 1; i <= maxn; i++) f[i] = i, num[i] = 1; cin>>n; char c; while(n--){ cin>>c>>m>>k; if(c == 'M'){ Union(m, k); } else{ query(m, k); } } return 0; }
例:Luogu P2256用map字串對映
#include<bits/stdc++.h> using namespace std; typedef long long ll; const int maxn = 2e5 + 5; ll n, m, k, sum; string s, r; priority_queue<int, vector<int>, greater<int> >q; map<string, string>ma; string f[maxn], a[maxn]; void initialise(){ for(int i = 0; i < maxn; i++){ ma[a[i]] = a[i]; } } string Find(string x){ if(ma[x] != x){ ma[x] = Find(ma[x]); } return ma[x]; } void Union(string x, string y){ string p = Find(x); string q = Find(y); if(p != q){ ma[p] = q; } } int main(){ //ios_base::sync_with_stdio(0); //cin.tie(); cout.tie(); cin>>n>>m; for(int i = 1; i <= n; i++){ cin>>a[i]; } initialise(); for(int i = 1; i <= m; i++){ cin>>s>>r; Union(s, r); } cin>>k; while(k--){ cin>>s>>r; string p = Find(s); string q = Find(r); if(p == q) cout<<"Yes."<<endl; else cout<<"No."<<endl; } return 0; }