互いに素設定テンプレートのHDU-1213

例:HDU 1213

//#include <bits/stdc++.h>
#include <iostream>
#include <stack>
#include <string>
#include <queue>
#include <stack>
#include <set>
#include <list>
#include <map>
#include <algorithm>
#include <string.h>
using namespace std;
 
const int MAXN = 1005;
int s[MAXN];
void init_set(){
    for(int i = 1; i <= MAXN; i++)
        s[i] = i;
}
 
int find_set(int x){
    return x = s[x]? x: find_set(s[x]);
}
 
void union_set(int x, int y){
    x = find_set(x);
    y = find_set(y);
    if(x != y) s[x] = s[y];
}
 
int main(){
    int t, n, m, x, y;
    cin >> t;
    while(t--){
        cin >> n >> m;
        init_set();
        for(int i = 1; i <= m; i++){
            cin >> x >> y;
            union_set(x, y);
        }
        int ans = 0;
        for(int i = 1; i <= n; i++){
            if(s[i] == i) ans++;
        }
        cout << ans << endl;
    }
    return 0;
}

上記の手順で、find_set()、union_set()は深さはO(N)、パフォーマンスの低下、次の最適化で検索し、検索組み合わせる複雑である最適化O(LOGN)。

図1に示すように、合成の最適化

XおよびYは、それらのルート最初の検索にマージされる場合、2つのルートノード、ルートノードの他に設定されたルートノードをマージします。小さい方の高さの方が大きいセットにマージは、ツリーの高さを低減することができる場合、これは、ルート・ノードの高さからも異なっています。次のコードは最適化され、高さがある[i]は再初期化は、素子Iの高さを定義します。

int height[MAXN];
void init_set(){
    for(int i = 1; i <= MAXN; i++){
        s[i] = i;
        height[i] = 0;
    }
}
 
void union_set(int x, int y){
    x = find_set(x);
    y = find_set(y);
    if(height[x] == height[y]){
        height[x] = height[x] + 1;
        s[y] = x;
    }
    else{
        if(height[x] < height[y]) s[x] = y;
        else s[y] = x;
    }
}

2、クエリの最適化 - 圧縮パス

上記のクエリプログラムfind_set()、私はあなたの検索パスのルートを見つける必要がある要素の問合せセットでは、結果は、ルートノードのリターンです。このパスは、非常に長いかもしれません。方法は、設定する場合、私は次の検索が時間内に結果を得ることができるようになり、その後とき、復帰時にルートノードに属しO(1)です。

次のような手順は以下のとおりです。

int find_set(int x){
    if(x != s[x])
        s[x] = find_set(s[x]);
    return s[x];
 
}

データが爆発スタックを心配する大きすぎる場合は、再帰的な実装を使用して上記のコードは、次の非再帰的なコードを使用することができます。

int find_set(int x){
    int r = x;
    while(s[r] != r)  //找到根节点
        r = s[r];
    int i = x, j;
    while(i != r){
        j = s[i];
        s[i] = r;
        i = j;
    }
    return r;
}

3、最適化は、完全なコードです

//#include <bits/stdc++.h>
#include <iostream>
#include <stack>
#include <string>
#include <queue>
#include <stack>
#include <set>
#include <list>
#include <map>
#include <algorithm>
#include <string.h>
using namespace std;
 
const int MAXN = 1005;
int s[MAXN];
int height[MAXN];
 
void init_set(){
    for(int i = 1; i <= MAXN; i++){
        s[i] = i;
        height[i] = 0;
    }
}
int find_set(int x){
    int r = x;
    while(s[r] != r)  //找到根节点
        r = s[r];
    int i = x, j;
    while(i != r){
        j = s[i];
        s[i] = r;
        i = j;
    }
    return r;
}
 
void union_set(int x, int y){
    x = find_set(x);
    y = find_set(y);
    if(height[x] == height[y]){
        height[x] = height[x] + 1;
        s[y] = x;
    }
    else{
        if(height[x] < height[y]) s[x] = y;
        else s[y] = x;
    }
}
 
int main(){
    int t, n, m, x, y;
    cin >> t;
    while(t--){
        cin >> n >> m;
        init_set();
        for(int i = 1; i <= m; i++){
            cin >> x >> y;
            union_set(x, y);
        }
        int ans = 0;
        for(int i = 1; i <= n; i++){
            if(s[i] == i) ans++;
        }
        cout << ans << endl;
    }
    return 0;
}

おすすめ

転載: www.cnblogs.com/lihello/p/11520738.html