最小生成树MST

定义

在一给定的无向联通带权图\(G = (V, E, W)\)中,\((u, v)\) 代表连接顶点 \(u\) 与顶点 \(v\) 的边,而 \(w(u, v)\) 代表此边的权重,若存在 \(T\)\(E\) 的子集,且为无循环图,使得 \(w(T)\) 最小,则此 \(T\)\(G\)最小生成树

其中\(w(T)=\sum\limits_{(u,v)∈t} w(u,v)\)

由定义易得,\(T\)中的边数为 顶点个数\(-1\)

实现算法常用\(Kruskal\)\(Prim\)

Kruskal 算法

将边按权值从小到大排序再依次放入图中,当整个图只有一个连通分量时,程序结束。

实现方法

  • 1.找到\(E\)中最小边
  • 2.判断边的两点是否在同一连通分量中
  • 3.若在,舍弃此边,转1。
  • 4.若不在,添加此边,将端点所在连通分量合并。
  • 5.所有边全选完后,若选边数为n-1,则输出解,否则无解处理。

代码:

#include <bits/stdc++.h>
using namespace std;
const int EDG=1000010;
const int VER=100010;
int n,m;
struct edge 
{
    int _start;
    int _end;
    int _weigh;
} arc[EDG];/*结构体存边,便于排序*/ 
bool cmp(edge a,edge b)
{
    return a._weigh<b._weigh;
}
int parent[VER];
inline void init();
inline int find(int x);
int union_(int x,int y);
inline bool search_(int x,int y);

int main()
{
    init();
    cin>>n>>m;
    for(int i=1;i<=m;i++)
    {
        cin>>arc[i]._start>>arc[i]._end>>arc[i]._weigh;
    }
    if(m<n-1)//如果不够n-1条边,直接无解 
    {
        cout<<"orz";
        return 0;
    }
    sort(arc+1,arc+1+m,cmp);//权值排序 
    int num=0;
    int ans=0;
    for(int i=1;i<=m;i++)
    {
        if(!search_(arc[i]._start,arc[i]._end))//如果边的端点不在同一个连通分量中 
        {
            ans+=arc[i]._weigh;//选择这条边 
            union_(arc[i]._end,arc[i]._start);//合并两个连通分量 
            num++;//选择的边数 +1 
        }
    }
    if(num==n-1)//最小生成树只可能有n-1条边 
    {
        cout<<ans;
    }
    else cout<<"orz";
}

/*----------并查集相关----------*/
inline void init()
{
    for(int i=0;i<=VER;i++)
    {
        parent[i]=i;
    }
}
inline int find(int x)
{
    int x_root=x;
    while(x_root!=parent[x_root])
    {
        x_root=parent[x_root];
    }
    while(x!=x_root)
    {
        int tmp=parent[x];
        parent[x]=x_root;
        x=tmp;
    }
    return x_root;
}
int union_(int x,int y)
{
    int x_root=find(x);
    int y_root=find(y);
    if(x_root==y_root) return 0;
    parent[x_root]=y_root;
    return 1;
}
inline bool search_(int x,int y)
{
    return find(x)==find(y);
}

Prim 算法

其实就是\(dijksrta\)的变种,配合理解即可

#include <bits/stdc++.h>
using namespace std;
const int INF=0x3f3f3f3f;
int edg[1010][1010];
int dis[100010];
int vis[100010];
int n;

void prim()
{
    int sum=0;
    memset(dis,0x3f,sizeof(dis));
    memset(vis,0,sizeof(vis));
    for(int i=1;i<=n;i++) dis[i]=edg[1][i];
    vis[1]=1;
    dis[1]=1;
    for(int i=1;i<n;i++)
    {
        int minn=INF;
        int u;
        for(int j=1;j<=n;j++)
        {
            if(!vis[j]&&minn>dis[j])
            {
                u=j;
                minn=dis[j];
            }
        }
        vis[u]=1;
        sum+=minn;
        for(int j=1;j<=n;j++)
        {
            if(!vis[j]&&edg[u][j]<dis[j])
            {
                dis[j]=edg[u][j];
            }
        }
    }
    cout<<sum;
}
int main()
{
    cin>>n;
    for(int i=1;i<=n;i++)
    {
        for(int j=1;j<=n;j++)
        {
            cin>>edg[i][j];
        }
    }
    prim();
    return 0;
}

原文链接: https://www.cnblogs.com/IzayoiMiku/p/13040398.html

欢迎关注

微信关注下方公众号,第一时间获取干货硬货;公众号内回复【pdf】免费获取数百本计算机经典书籍;

也有高质量的技术群,里面有嵌入式、搜广推等BAT大佬

    最小生成树MST

原创文章受到原创版权保护。转载请注明出处:https://www.ccppcoding.com/archives/352643

非原创文章文中已经注明原地址,如有侵权,联系删除

关注公众号【高性能架构探索】,第一时间获取最新文章

转载文章受原作者版权保护。转载请注明原作者出处!

(0)
上一篇 2023年3月2日 上午7:39
下一篇 2023年3月2日 上午7:39

相关推荐