加载中...

最小生成树

\[最小生成树 \begin{cases} \ Prim算法 \quad \begin{cases}\ 朴素版Prim\ \\[3ex] 堆优化版Prim\ \end{cases}\ \\[5ex] Kruskal算法 \end{cases}\ \]



Prim算法

朴素Prim基本思想:

dist [ i ] \(\longleftarrow\) + \(\infty\)

for (int i = 0 ; i < n ; i ++)

​$\quad$ $\quad$ t \(\longleftarrow\) 找到集合外距离最近的点

​$\quad$ $\quad$ 用t更新其他点到集合的距离

​$\quad$ $\quad$ st [ t ] = true


//朴素版Prim算法模板

int n;		//表示点数
int g[N][N];	//邻接矩阵,存储所有边
int dist[N];	//存储其他点到当前最小生成树的距离
bool st[N];		//存储每个点是否已经在生成树中

//如果图不连通则返回INF(值是0x3f3f3f3f),否则返回最小生成树的树边权重之和
int prim()
{
    memset(dist,0x3f,sizeof dist);
    
    int res=0;
    for(int i=0;i<n;i++)
    {
        int t=-1;
        for(int j=1;j<=n;j++)
            if(!st[j]&&(t==-1||dist[t]>dist[j]))
                t=j;
        
        if(i&&dist[t]==INF)return INF;
        
        if(i)res+=dist[t];
        st[t]=true;
        
        for(int j=1;j<=n;j++)dist[j]=min(dist[j],g[t][j]);
    }
    
    return res;
}



Kruskal 算法

Kruskal算法基本思想:

① 将所有边按权重从小到大排序

② 枚举每一条边 a \(\to\) b ,权重c

​$\quad$ $\quad$ if a、b 不连通

​$\quad$ $\quad$ $\quad$ 将这条边加入集合中


//Kruskal算法模板

int n,m;	//n是点数,m是边数
int p[N];	//并查集的父节点数组

int find(int x)		//并查集核心操作
{
    if(p[x]!=x)p[x]=find(p[x]);
    return p[x];
}

struct Edge		//存储边
{
    int a,b,w;
    
    bool operator<(const Edge &W)const
    {
        return w<W.w;
    }
}edges[M];

int kruskal()
{
    sort(edges,edges+m);
    
    for(int i=1;i<=n;i++)p[i]=i;	//初始化并查集
    
    int res=0,cnt=0;
    for(int i=0;i<m;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;
            cnt++;
        }
    }
    
    if(cnt<n-1)return INF;
    return res;
}


posted @ 2023-04-28 14:01  邪童  阅读(14)  评论(0编辑  收藏  举报