1. 程式人生 > 實用技巧 >Spring-boot整合pg、mongo多資料來源過程詳解

Spring-boot整合pg、mongo多資料來源過程詳解

並查集就是給你一個圖,裡面有很多點,並就是把點合併一個集合,把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父親 int
q = 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;
}