山东大学数据结构实验13 最小生成树

发布时间 2023-04-25 21:20:38作者: Lyz103

Prime算法

描述

使用prim算法实现最小生成树

格式

输入

第一行两个整数n,e。n (\(1 \leq n \leq 200000\)) 代表图中点的个数,e (\(0 \leq m \leq 500000\)) 代表边的个数。
接下来e行,每行代表一条边:

  • i j w 表示顶点i和顶点j之间有一条权重为w的边

输出

最小生成树所有边的权重和

样例

输入

7 12
1 2 9
1 5 2
1 6 3
2 3 5
2 6 7
3 4 6
3 7 3
4 5 6
4 7 2
5 6 3
5 7 6
6 7 1

输出

16

限制

1s, 10240KiB for each test case.

#include <cstring>
#include <iostream>
#include <algorithm>
#include <queue>
#include<cstdio>
//from yuanzi
//prim
using namespace std;

typedef pair<int, int> PII;

const int N = 1e6 + 10;

int n, m;
int dist[N];
bool st[N];

struct graphNode {
    int element;
    graphNode *next;
    int weight;

    graphNode(int e, graphNode *node, int w) {
        element = e;
        next = node;
        weight = w;
    }
};

struct graphChain {
    graphNode *firstNode;
    graphNode *lastNode;
};

class graph {
public:
    graph(int num = 0) {
        node = num;
        edge = 0;
        aList = new graphChain[node + 1];
        for (int i = 0; i <= node; i++) {
            aList[i].firstNode = nullptr;
        }

    }

    ~graph() { delete[]aList; }

    void insert(int v1, int v2, int w);

    long long prim();

private:
    int node;//the number of node
    int edge;//the number of edge
    graphChain *aList;
};

void graph::insert(int v1, int v2, int w) {
    if (aList[v1].firstNode == nullptr) { aList[v1].firstNode = aList[v1].lastNode = new graphNode(v2, nullptr, w); }
    else {

        aList[v1].lastNode->next = new graphNode(v2, nullptr, w);
        aList[v1].lastNode = aList[v1].lastNode->next;
    }

}

long long graph::prim() {

    long long res = 0;
    memset(dist, 0x3f, sizeof dist);
    dist[1] = 0;
    priority_queue<PII, vector<PII>, greater<PII>> heap;//小根堆初始化
    heap.push({0, 1});

    while (!heap.empty()) {
        auto t = heap.top();
        heap.pop();

        int ver = t.second, distance = t.first;

        if (st[ver]) continue;
        st[ver] = true;
        dist[ver] = 0;
        res += distance;
        for (graphNode *Node = aList[ver].firstNode; Node; Node = Node->next) {
            int j = Node->element;
            if (dist[j] > Node->weight) {
                dist[j] = Node->weight;
            }
            if (!st[j]) heap.push({dist[j], j});
        }
    }

    return res;
}

int main() {
    scanf("%d%d", &n, &m);
    int v1, v2, c;
    graph a(n);
    while (m--) {
        cin >> v1 >> v2 >> c;
        a.insert(v1, v2, c);
        a.insert(v2, v1, c);
    }

    cout << a.prim() << endl;

    return 0;
}

克鲁斯卡尔算法

(不开long long见祖宗)

描述

使用kruskal算法实现最小生成树

格式

输入

第一行两个整数n,e。n (\(1 \leq n \leq 200000\)) 代表图中点的个数,e (\(0 \leq m \leq 500000\)) 代表边的个数。
接下来e行,每行代表一条边:

  • i j w 表示顶点i和顶点j之间有一条权重为w的边

输出

最小生成树所有边的权重和

样例

输入

7 12
1 2 9
1 5 2
1 6 3
2 3 5
2 6 7
3 4 6
3 7 3
4 5 6
4 7 2
5 6 3
5 7 6
6 7 1

输出

16

限制

1s, 10240KiB for each test case.

#include <cstring>
#include <iostream>
#include <algorithm>

using namespace std;

const int N = 200010, M = 500010;


int p[N];

struct Edge {
    int a, b, w;

    bool operator<(const Edge &W) const {
        return w < W.w;
    }
};


int find(int x) {
    if (p[x] != x) p[x] = find(p[x]);
    return p[x];
}//找到并查集的祖宗,并且进行路径压缩优化

class graph {
public:
    graph(int num, int point) {
        edges = new Edge[num];
        this->num = num;
        this->point = point;
    }

    long long kruskal();

    void set(int a, int b, int w, int i) {
        edges[i] = {a, b, w};
    }

private:
    int n;
    int num;
    int point;
    struct Edge *edges;
};

long long graph::kruskal() {
    sort(edges, edges + num);

    for (int i = 1; i <= point; i++) p[i] = i;    // 初始化并查集

    long long res = 0;
    for (int i = 0; i < num; i++) {
        int a = edges[i].a,
                b = edges[i].b,
                w = edges[i].w;
        a = find(a), b = find(b);
        if (a != b) {
            p[a] = b;
            res += w;
        }
    }
    return res;
}

int main() {
    int n, m;
    cin >> n >> m;
    graph g(m, n);

    for (int i = 0; i < m; i++) {
        int a, b, w;
        cin >> a >> b >> w;
        g.set(a, b, w, i);
    }

    cout << g.kruskal() << endl;


    return 0;
}