互いに素セットとクラスカル最小スパニングツリーアルゴリズム

まず、互いに素セットは何ですか

コンピュータサイエンスでは、いくつかの問題との統合との契約のための木の素集合データ構造は、クエリのセットをばらばら。あり、関節-検索アルゴリズムが(組合-検索アルゴリズム)データ構造のための2つの動作時間を定義します。

  • 検索:属する要素のどのサブセットを決定します。2つの要素は同じサブセットに属するかどうかを決定するために使用することができます。
  • 連合:2つのサブセットとコレクションに。

第二に、主な操作

  • 初期化:独自のコレクションの各ポイントを初期化します。
for(int i=1;i<=n;i++)
    f[i]=i;
  • 検索:ルート・ノードである位置してい要素のセットを検索します。
int find(int x)
{
    while(f[x]!=x)
        x=f[x];
    return x;
}
  • マージ:つの収集に結合素子の二組。
void Union(int x1,int x2)
{
    int t1=find(x1);
    int t2=find(x2);
    if(t1!=t2)
        f[t2]=t1;
}

第三に、最適化

上記のコードは、単純なようだが、各検索操作の時間計算量はO(H)で、私たちは木に特別な治療をしなかったので、Hは、木の高さなので、木は木が深刻な不均衡を引き起こす可能性がマージし続け最悪の場合、各ノードは、唯一の子ノードを持っています。

したがって、検索機能は、で使用パス圧縮

int find(int x)       //查找x元素所在的集合,回溯时压缩路径
{
    if (x != f[x])
    {
        f[x] = find(f[x]); 
        //从x结点搜索到祖先结点所经过的结点都指向该祖先结点
    }         
    return f[x];
}

第四に、テンプレートのタイトル

羅区P3367 [テンプレート]互いに素セット

#include<bits/stdc++.h>
using namespace std;
int n,m;
int f[10002];
int find(int x)
{
    if(x!=f[x])
        f[x]=find(f[x]);
    return f[x];
}
void Union(int x1,int x2)
{
    int t1=find(x1);
    int t2=find(x2);
    if(t1!=t2) //祖先不一样 
        f[t2]=t1; //把t2的祖先变为x1的祖先t1 
}
int main()
{
    cin>>n>>m;
    for(int i=1;i<=n;i++)
        f[i]=i;
    for(int i=0;i<m;i++)
    {
        int z,x,y;
        cin>>z>>x>>y;
        if(z==1)
            Union(x,y); 
        else
        {
            if(find(x)!=find(y))cout<<"N"<<endl;
            else cout<<"Y"<<endl;
        }
    }
    return 0;
}

第五に、最小スパニングツリー

原画像のn個の頂点を有する連結グラフはn個のノードのすべてが元の画像を含む、最小スパニングツリーリンク部分グラフであり、図を保ちながら最小の通信があります。

最小スパニングツリーは、実際には、最小重量スパニングツリーと呼ばれています。

クラスカル法

  • 昇順のグラフ体重に応じてすべてのエッジ
  • ループを構成する場合にソートされたすべてのエッジを横切る、その後縁がコレクションに追加され
  • これは、n-1辺を見つけるまで

例:忙しい都市

#include<bits/stdc++.h>
using namespace std;
int n,m;
int s,maxm;
int p[100002];
struct node{
    int u;
    int v;
    int c;
}info[100002];

bool cmp(node x1,node x2)
{
    if(x1.c!=x2.c)return x1.c<x2.c;
    else if(x1.u!=x2.u) return x1.u<x2.u;
    else return x1.v<x2.v;
}
int find(int x)       //查找x元素所在的集合,回溯时压缩路径
{
    if (x!=p[x])
    {
        p[x]=find(p[x]);  
    }         
    return p[x];
}
void bcj(int x1,int x2)//把x2并入x1的集合
{
    int t1,t2;//存储祖先节点
    t1=find(x1);
    t2=find(x2);
    if(t1!=t2)p[t2]=t1;
}
int main()
{
    cin>>n>>m;//n就是顶点数,m是边数
    for(int i=1;i<=n;i++)
    {
        p[i]=i;
    }
    for(int i=0;i<m;i++)
    {
        cin>>info[i].u>>info[i].v>>info[i].c;
    }
    sort(info,info+m,cmp);
    for(int i=0;i<m;i++)//遍历所有的边
    {
        if(find(info[i].u)!=find(info[i].v))
        {
            bcj(info[i].u,info[i].v);//把v并入u的集合
            maxm=max(maxm,info[i].c);
        }
    }
    cout<<n-1<<" "<<maxm;
    return 0;
}

おすすめ

転載: www.cnblogs.com/jiyi-conding/p/11795008.html