[8]アルゴ&DS最小スパニングツリー

1.はじめに最小スパニングツリー

最小スパニングツリーは何ですか?

最小スパニングツリー(最小スパニングツリー、MST)与えられた無向グラフG(V、E)Tで、ツリーを求め、グラフGの頂点の全てを有するツリー、およびすべての側面から来ますさエッジグラフG、及び満足ツリー全体、エッジ重みの最小値。

2.primアルゴリズム

ダイクストラ法など!図のGIFは、アルゴリズムのプリム核となるアイデアは、図2に設けられているS G(V、E)を設定し、以下、頂点が訪問された店舗、及び最小の各選択との最短距離SをセットVSから頂点の集合である(参照)uと表記し、コレクションS.へのアクセス その後、頂点uのようにUおよびVセットSから到達可能な全ての頂点間の最小距離間の中間点。集合sは、すべての頂点を含むようになるまでこの操作では、n回行われます。

プリム

差からダイクストラ法DIST、あるソースS Wの最短経路の頂点へプリムアルゴリズムDIST、W頂点集合Sからの最短経路であるダイクストラ法で、それらの擬似コード記述比較以下詳細な説明はしてください資料を参照してください。

Snipaste_2019-11-24_15-30-32

アルゴリズム:

#include<iostream>
#include<vector>
#define INF 100000
#define MaxVertex 105
typedef int Vertex; 
int G[MaxVertex][MaxVertex];
int parent[MaxVertex];   // 并查集 
int dist[MaxVertex]; // 距离 
int Nv;    // 结点 
int Ne;    // 边 
int sum;  // 权重和 
using namespace std; 
vector<Vertex> MST;  // 最小生成树 

// 初始化图信息 
void build(){
    Vertex v1,v2;
    int w;
    cin>>Nv>>Ne;
    for(int i=1;i<=Nv;i++){
        for(int j=1;j<=Nv;j++)
            G[i][j] = 0;  // 初始化图 
        dist[i] = INF;   // 初始化距离
        parent[i] = -1;  // 初始化并查集 
    }
    // 初始化点
    for(int i=0;i<Ne;i++){
        cin>>v1>>v2>>w;
        G[v1][v2] = w;
        G[v2][v1] = w;
    }
}

// Prim算法前的初始化 
void IniPrim(Vertex s){
    dist[s] = 0;
    MST.push_back(s);
    for(Vertex i =1;i<=Nv;i++)
        if(G[s][i]){
            dist[i] = G[s][i];
            parent[i] = s;
        } 
}

// 查找未收录中dist最小的点 
Vertex FindMin(){
    int min = INF;
    Vertex xb = -1;
    for(Vertex i=1;i<=Nv;i++)
        if(dist[i] && dist[i] < min){ 
            min = dist[i];
            xb = i;
        }
    return xb;
}

void output(){
    cout<<"被收录顺序:"<<endl; 
    for(Vertex i=1;i<=Nv;i++)
        cout<<MST[i]<<" ";
    cout<<"权重和为:"<<sum<<endl; 
    cout<<"该生成树为:"<<endl; 
    for(Vertex i=1;i<=Nv;i++)
        cout<<parent[i]<<" ";
}

void Prim(Vertex s){
    IniPrim(s);
    while(1){
        Vertex v = FindMin();
        if(v == -1)
            break;
        sum += dist[v];
        dist[v] = 0;
        MST.push_back(v);
        for(Vertex w=1;w<=Nv;w++)
            if(G[v][w] && dist[w])
                if(G[v][w] < dist[w]){
                    dist[w] = G[v][w];
                    parent[w] = v;
                }
    }
}


int main(){
    build();
    Prim(1);
    output();
    return 0;
} 

プリムのアルゴリズムについてのより詳細な説明は、してくださいビデオを参照してください。

3.kruskalアルゴリズム

クラスカルのアルゴリズムはまた、問題の最小スパニングツリーを解決するために使用することができ、アルゴリズムのアイデアは、典型的に理解するのは簡単です貪欲エッジを、アルゴリズムが考えました:

  • 図は、各頂点が単一の通信ブロックを描いているように、すべてのエッジの初期状態では、n個のブロック通信の合計色あせ
  • 小規模から大規模なソートへのすべてのサイド・バイ・サイド、右
  • 押している場合、すべての側面が、大規模なテストに小さいからエッジ重み現在の試験頂点の両側は、通信ブロックと接続されていない現在の最小スパニングツリーを加えながら、試験を置くが、それ以外の場合は、エッジを破棄する。
  • 最小スパニングツリーのエッジの数まで、前のステップを繰り返すこと頂点マイナス時間の終わりの合計数に等しいか、またはすべての側面をテストして、終了した場合、最小スパニングツリーの辺の数は数字は通信しないことを示す、頂点の総数から1を引いたものよりも少ないです。

以下のGIFマップを考えてみましょう!

クラスカル

アルゴリズム:

#include<iostream>
#include<string>
#include<vector>
#include<queue>
#define INF 100000
#define MaxVertex 105
typedef int Vertex; 
int G[MaxVertex][MaxVertex];
int parent[MaxVertex];   // 并查集最小生成树 
int Nv;    // 结点 
int Ne;    // 边 
int sum;  // 权重和 
using namespace std; 
struct Node{
    Vertex v1;
    Vertex v2;
    int weight; // 权重 
    // 重载运算符成最大堆 
    bool operator < (const Node &a) const
    {
        return weight>a.weight;
    }
};
vector<Node> MST;  // 最小生成树 
priority_queue<Node> q;   // 最小堆 

// 初始化图信息 
void build(){
    Vertex v1,v2;
    int w;
    cin>>Nv>>Ne;
    for(int i=1;i<=Nv;i++){
        for(int j=1;j<=Nv;j++)
            G[i][j] = 0;  // 初始化图
        parent[i] = -1;
    }
    // 初始化点
    for(int i=0;i<Ne;i++){
        cin>>v1>>v2>>w;
        struct Node tmpE;
        tmpE.v1 = v1;
        tmpE.v2 = v2;
        tmpE.weight = w;
        q.push(tmpE); 
    }
}

//  路径压缩查找 
int Find(int x){
    if(parent[x] < 0)
        return x;
    else
        return parent[x] = Find(parent[x]);
} 

//  按秩归并 
void Union(int x1,int x2){
    if(parent[x1] < parent[x2]){
        parent[x1] += parent[x2];
        parent[x2] = x1;
    }else{
        parent[x2] += parent[x1];
        parent[x1] = x2;
    }
} 

void Kruskal(){
    // 最小生成树的边不到 Nv-1 条且还有边 
    while(MST.size()!= Nv-1 && !q.empty()){
        Node E = q.top();  // 从最小堆取出一条权重最小的边
        q.pop(); // 出队这条边 
        if(Find(E.v1) != Find(E.v2)){  // 检测两条边是否在同一集合 
            sum += E.weight; 
            Union(E.v1,E.v2);     // 并起来 
            MST.push_back(E);
        }
    }
    
} 


void output(){
    cout<<"被收录顺序:"<<endl; 
    for(Vertex i=0;i<Nv;i++)
        cout<<MST[i].weight<<" ";
    cout<<"权重和为:"<<sum<<endl; 
    for(Vertex i=1;i<=Nv;i++)
        cout<<parent[i]<<" ";
    cout<<endl;
}


int main(){
    build();
    Kruskal();
    output();
    return 0;
} 

クラスカルのアルゴリズムについてより詳細に説明され、ビデオを参照してください。

おすすめ

転載: www.cnblogs.com/ericling/p/11922816.html