prim求最小生成树

Posted sugewud

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了prim求最小生成树相关的知识,希望对你有一定的参考价值。

一直以来只会Kruskal

prim和dijkstra很像

只不过prim维护的是最短的边,而dijkstra维护的是最短的从起点到一个点的路径

同时prim要注意当前拓展的边是没有拓展过的

可以用堆优化

#include<bits/stdc++.h>
#define REP(i, a, b) for(register int i = (a); i < (b); i++)
#define _for(i, a, b) for(register int i = (a); i <= (b); i++)
using namespace std;

const int MAXN = 5000 + 10;
const int MAXM = 2e5 + 10;

struct Edge{ int to, w, next; };
Edge e[MAXM << 1];
int head[MAXN], d[MAXN], vis[MAXN], n, m, tot;

void AddEdge(int from, int to, int w)
{
    e[tot] = Edge{to, w, head[from]};
    head[from] = tot++;
}

void read(int& x)
{
    int f = 1; x = 0; char ch = getchar();
    while(!isdigit(ch)) { if(ch == -) f = -1; ch = getchar(); }
    while(isdigit(ch)) { x = x * 10 + ch - 0; ch = getchar(); }
    x *= f;
}

void prim()
{
    vis[1] = 1;
    _for(i, 1, n) d[i] = i == 1 ? 0 : 1e9;
    for(int i = head[1]; ~i; i = e[i].next)
    {
        int v = e[i].to;
        d[v] = min(d[v], e[i].w);
    }
    
    int ans = 0;
    REP(k, 1, n)
    {
        int mint = 1e9, id;
        _for(i, 1, n)
            if(!vis[i] && d[i] < mint)
            {
                mint = d[i];
                id = i;
            }
        
        ans += mint;
        vis[id] = 1;
        
        for(int i = head[id]; ~i; i = e[i].next)
        {
            int v = e[i].to;
            if(vis[v]) continue;
            d[v] = min(d[v], e[i].w);
        }
    }
    printf("%d
", ans);
}

int main()
{
    memset(head, -1, sizeof(head)); tot = 0;
    read(n); read(m);
    _for(i, 1, m)
    {
        int u, v, w;
        read(u); read(v); read(w);
        AddEdge(u, v, w);
        AddEdge(v, u, w);
    }
    prim();
    return 0;
}

堆优化版本

#include<bits/stdc++.h>
#define REP(i, a, b) for(register int i = (a); i < (b); i++)
#define _for(i, a, b) for(register int i = (a); i <= (b); i++)
using namespace std;

const int MAXN = 5000 + 10;
const int MAXM = 2e5 + 10;

struct Edge{ int to, w, next; };
Edge e[MAXM << 1];
int head[MAXN], d[MAXN], vis[MAXN], n, m, tot;

void AddEdge(int from, int to, int w)
{
    e[tot] = Edge{to, w, head[from]};
    head[from] = tot++;
}

void read(int& x)
{
    int f = 1; x = 0; char ch = getchar();
    while(!isdigit(ch)) { if(ch == -) f = -1; ch = getchar(); }
    while(isdigit(ch)) { x = x * 10 + ch - 0; ch = getchar(); }
    x *= f;
}

struct node
{
    int id, w;
    bool operator < (const node& rhs) const
    {
        return w > rhs.w;
    }
};
priority_queue<node> q;

void prim()
{
    vis[1] = 1;
    _for(i, 1, n) d[i] = i == 1 ? 0 : 1e9;
    for(int i = head[1]; ~i; i = e[i].next)
    {
        int v = e[i].to;
        d[v] = min(d[v], e[i].w);
    }
    _for(i, 1, n) q.push(node{i, d[i]});
    
    int ans = 0;
    REP(k, 1, n)
    {
        int mint, id;
        while(1)
        {
            node x = q.top(); q.pop();
            if(vis[x.id]) continue;
            id = x.id, mint = x.w;
            break;
        }

        ans += mint;
        vis[id] = 1;
        
        for(int i = head[id]; ~i; i = e[i].next)
        {
            int v = e[i].to;
            if(vis[v]) continue;
            if(d[v] > e[i].w) 
            {
                d[v] = e[i].w;
                q.push(node{v, d[v]});
            }
        }
    }
    printf("%d
", ans);
}

int main()
{
    memset(head, -1, sizeof(head)); tot = 0;
    read(n); read(m);
    _for(i, 1, m)
    {
        int u, v, w;
        read(u); read(v); read(w);
        AddEdge(u, v, w);
        AddEdge(v, u, w);
    }
    prim();
    return 0;
}

 

 

 

以上是关于prim求最小生成树的主要内容,如果未能解决你的问题,请参考以下文章

急!数据结构最小生成树prim算法C语言实现

最小生成树的prim算法 边的权值为啥不能为负值

最小生成树的prim算法 边的权值为啥不能为负值

Prim算法和Kruskal算法求最小生成树

prim和kruscal算法得到的最小生成树是不是一样

急求KRUSKAL算法求最小生成树过程演示