prim算法

发布时间 2023-11-01 00:48:54作者: zhuwen

prim—最小生成树

模板—最小生成树

int n,m,s;
int ne[N],h[N],idx,e[N],wt[N];//wt[]表示边权

void add(int u,int v,int w) //链式前向星存图
{
    idx++;
    e[idx]=v;
    wt[idx]=w; //边权
    ne[idx]=h[u];
    h[u]=idx;
}

int vis[N]; //vis[i]表示i点是否在s集合中
int d[N]; //d[i]表示 s->i 的最短路径

int p[N]; //p[i]表示i点是从哪个点过来的

int prim(int s)// 时间复杂度O(n^2);
{
    int ans=0;
    for(int i=1;i<=n;i++)
    {
        d[i]=INF;
        //如果多次求d
        //要更新vis[]
        //要更新p[]
    }
    d[s]=0;
    //执行n次把点从t集合到s集合
    for(int i=1;i<=n;i++)
    {
        //1,找到最短路u
        int u=0;
        int minn=INF;
        for(int j=1;j<=n;j++)
        {
            //s集合与t集合的最短边
            if(d[j]<minn&&vis[j]==0)
            {
                u=j;
                //把最小值的下标给u
                minn=d[j];
                //把最小值给minn
            }
        }

        //2,把u移到s集合中
        vis[u]=1; //移到s集合中
        if(u==0)
        {
            return -1;
        }
        ans+=d[u];
        //3,在t集合中,跟u相邻的点进行松弛操作
        for(int j=h[u];j;j=ne[j])
        {
            int v=e[j];
            int w=wt[j];
            if(vis[v]==0&&d[v]>w)
            {
                d[v]=w;
            }
        }
    }
    return ans;
}
signed main()
{   fst;
    n=read(),m=read();
    for(int i=1;i<=m;i++)
    {
        int u,v,w;
        u=read();
        v=read();
        w=read();
        add(u,v,w); //存图
        add(v,u,w);
    }
    int q=prim(1);
    if(q==-1)
    {
        cout<<"orz"<<endl;
    }
    else
    {
        cout<<q<<endl;
    }
    return 0;
}
int n, m, s;//堆优化
bool vis[N];
int d[N];

// 点u,d[u]

struct vnode
{
    int p;                               // 点
    int d;                               // 距离
    bool operator<(const vnode &b) const // 小顶堆——重载运算符
    {
        return d > b.d;
    }
};
vector<vnode> g[N];

int ans = 0;

int prim(int s)
{
    priority_queue<vnode> q;
    for (int i = 1; i <= n; i++)
    {
        d[i] = INF;
    }
    d[s] = 0;
    q.push({s, 0});
    while (!q.empty())
    {
        int u = q.top().p; // 找顶堆元素
        q.pop();
        if (vis[u]) // 如果已经找到了,就不用再操作了
        {
            continue;
        }
        // 如果在s集合中,就不用操作了,只有在t集合中,我们才拿进去,然后松弛
        vis[u] = 1;
        ans += d[u];
        for (auto e : g[u])
        {
            int v = e.p;
            int w = e.d;
            if (vis[v] == 0 && d[v] > w)
            {
                d[v] = w;
                q.push({v, d[v]});
            }
        }
    }
}
signed main()
{
    fst;
    cin >> n >> m;
    for (int i = 1; i <= m; i++)
    {
        int u, v, w;
        cin >> u >> v >> w;
        g[u].pb({v, w});
        g[v].pb({u, w});
    }
    prim(1);
    for (int i = 1; i <= n; i++)
    {
        if (d[i] == INF)
        {
            cout << "orz" << endl;
            return 0;
        }
    }
    cout << ans << endl;
    return 0;
}

与Dijkstra算法类似,就在最后松弛操作时不同