最小生成树

1.prim

每次循环都访问一个点,并将此点所有边找到其最小的边权,如果最小边权对应的点没有被访问过,则加入队列。这相当于向生成树中添加了n-1条最小边,最后检查所有点的连通性,联通的话得到的就是最小生成树,属于贪心算法。

暴力贪心的话复杂度为o(n²),这边采用堆优化的方法,时间复杂度o(mlogn)

const int N = 2e5 + 10, INF = 0x3f3f3f3f3f3f3f3f;
int dis[N];
bool vis[N];
int n, m, sum;
vector<pair<int, int>> vt[N];
priority_queue<pair<int, int>, vector<pair<int, int>>, greater<pair<int,int>>> q;
int prim(int pos) {
    int ans = 0;
    int cnt = 0;
    q.push(make_pair(0, pos));
    while (!q.empty() && cnt <= n) {
        int x = q.top().first;
        int y = q.top().second;
        q.pop();
        if (vis[y])continue;
        vis[y] = true;
        ans += x; cnt++;
        for (auto it : vt[y])
            if (!vis[it.first])
                q.push(make_pair(it.second, it.first));
    }
    return ans;
}
void solve() {
    cin >> n >> m;
    memset(dis, INF, sizeof(dis));
    for (int i = 1; i <= m; i++) {
        int u, v, w;
        cin >> u >> v >> w;
        vt[u].push_back(make_pair(v, w));
        vt[v].push_back(make_pair(u, w));
    }
    int value = prim(1);
    int flag = 0;
    for (int i = 1; i <= n; i++)
        if (!vis[i])flag = 1;
    if (value >= INF || flag)cout << "orz" << endl;
    else cout << value << endl;
}

跟最短路的代码有些相似。

 

2、kruskal

将所有边进行排序后利用并查集将点连成一个集合,最后检查一下所有点是否在同一个集合内,是的话则输出最小生成树。

const int N = 2e5 + 10, INF = 0x3f3f3f3f3f3f3f3f;
int f[N];
int n, m, sum;
struct edge {
    int u, v, w;
}ed[N];
void start() {
    for (int i = 1; i <= n; i++)f[i] = i;
}
bool cmp(edge k, edge l) {
    return k.w < l.w;
}
int find(int x) {
    if (x == f[x])return x;
    f[x] = find(f[x]);
    return f[x];
}
int kruskal() {
    int ans = 0;
    int cnt = 0;
    for (int i = 1; i <= m; i++){
        int fu = find(ed[i].u);
        int fv = find(ed[i].v);
        if (fu != fv) {
            f[fu] = fv;
            ans += ed[i].w;
            cnt++;
        }
        if (cnt == n - 1)return ans;
    }
    return -1;
}
void solve() {
    cin >> n >> m;
    start();
    for (int i = 1; i <= m; i++)
        cin >> ed[i].u >> ed[i].v >> ed[i].w;
    sort(ed + 1, ed + 1 + m, cmp);
    int temp = kruskal();
    int cnt = 0;
    for (int i = 1; i <= n; i++)
        if (f[i] == i)cnt++;
    if (cnt > 1)temp = -1;
    if (temp != -1)cout << temp << endl;
    else cout << "orz" << endl;
}

 

 

 
posted @ 2023-08-05 19:47  DLSQS  阅读(50)  评论(0)    收藏  举报