最小スパニング ツリー アルゴリズムの学習の概要

n 個のノードを持つ 接続 元のグラフの n 個のノードすべてを含み、グラフの接続を維持する最小のエッジを持つ元のグラフの最小の接続サブグラフです。最小スパニングツリーは、 kruskal (Kruskal) アルゴリズムまたは prim (Prime) アルゴリズムによって取得できます。

1. プリムアルゴリズム

Prim アルゴリズムは毎回設定された点に最も近い点を見つける必要があるため、その時間計算量は頂点 V の数に関係します。つまり、次はPrim アルゴリズムのテンプレートです。

const int INF = 100000000;
const int maxv = 1000;
int n, G[maxv][maxv];//邻接矩阵存储图
bool vis[maxv];
int dis[maxv];
 
int prim(){
    fill(dis, dis + maxv, INF); 
    fill(vis, vis + maxv, 0); //初始默认所有点独立
    dis[0] = 0;//把点0加入集合
    for (int i = 0; i <= n; i++){
        int u = -1, MIN = INF;
        for (int j = 0; j <= n; j++){
            if (!vis[j] && dis[j] < MIN) { //如果这个点没有加入集合S,且到集合的距离更短
                MIN = dis[j];//更新点V到集合S的最小值
                u = j;//把点赋给u
            }
        }
        if (u == -1) return -1; //图不连通
        vis[u] = true;//如果找到了这个点,就把它加入集合S
        for (int v = 0; v <= n; v++) dis[v] = min(dis[v], G[u][v]);//用新加入的点更新dis[]
    }
}

2. クラスカルアルゴリズム

Kuraskal アルゴリズムではエッジの 2 つの頂点が同じ接続されたブロックに属するかどうかを判断する必要がありますが、これは和集合検索で判断できるため、和集合検索の知識を補足する必要があります。

#define SIZE 13
int UFSets[SIZE];

void Initial(int S[]) {
    for (int i = 0; i < SIZE; i++)
        S[i] = -1;
}

int Find(int S[], int x) {
    int root = x;
    while (S[root] >= 0)root = S[root];
    //路径压缩
    while (x != root) {
        int t = S[x];
        S[x] = root;
        x = t;
    }
    return root;
}

void Union(int S[], int Root1, int Root2) {
    if (Root1 == Root2) return;
    if (S[Root2] > S[Root1]) { //Root2结点数更少
        S[Root1] += S[Root2];
        S[Root2] = Root1;
    } else {
        S[Root2] += S[Root1];
        S[Root1] = Root2;
    }
}

以下は Kruskal アルゴリズムのテンプレートです。時間計算量は次のとおりです

書き方や確認方法に注意しないと無限ループになりやすい

const int maxv = 1000;
const int maxe = 300;
int UFSets[100]; //并查集大小
int n, G[maxv][maxv];//n个顶点
int Enum = 0;//边的总数

struct edge {
    int from;
    int to;
    int cost;
}E[maxe];

bool cmp(edge a, edge b) {
    return a.cost < b.cost;
}

int Find(int S[], int x) {
    int root = x;
    while (S[root] >= 0)root = S[root];
    //路径压缩
    while (x != root) {
        int t = S[x];
        S[x] = root;
        x = t;
    }
    return root;
}

int Kruskal() {
    int num_edge = 0; //n+1个顶点最小生成树应该有n条边
    fill(UFSets, UFSets + n + 1, -1); //fill(10):a[0]-a[9]
    sort(E, E + Enum, cmp);//所有边按权从小到大排序
    for (int i = 0; i < Enum; i++) {
        int a = Find(UFSets, E[i].from);
        int b = Find(UFSets, E[i].to);
        if (a != b) { //不在同一个连通块中 
            UFSets[a] = b; //将其放入同一个连通块中
            num_edge++;
            if (num_edge == n)break; //最小生成树创建完成
        }
    }
    if (num_edge != n) return -1; //图不连通返回-1 
    else return 1;
}

おすすめ

転載: blog.csdn.net/qq_21891843/article/details/129686944