AcWing算法提高课 最小生成树

一般使用kruskal(克鲁斯卡尔)(mlogm)

对于稀疏图,用朴素prim(n^2)

prim:每次选择和当前已经构建出的连通块相连,且权重最小的边,加入当前连通块。

一共需要扩展(n-1)次

只能处理一个连通块,不能“生成森林”

 

 例题:https://www.acwing.com/problem/content/1142/

模板:

int n;
const int N=110;
int adj[N][N];
int dis[N];
bool st[N];

int Prim()
{
    int res=0;
    memset(dis,0x3f,sizeof(dis));
    dis[1]=0;

    for(int i=0;i<n;i++)
    {
        int t=-1;
        for(int j=1;j<=n;j++)
        {
            if(!st[j]&&(t==-1||dis[t]>dis[j]))
            {
                t=j;
            }
        }
        res+=dis[t];
        st[t]=true;
        for(int j=1;j<=n;j++)
        {
            dis[j]=min(dis[j],adj[t][j]);
        }
    }
    return res;
}
View Code

 

 kruskal:基于并查集。先将所有边从小到大排序,然后枚举每条边,如果边的两个端点还不联通,则将当前边加入最小生成树。

例题:

https://www.acwing.com/problem/content/1143/

模板:

vector<PIII> edges;
int p[N];
int find(int x)
{
    if(p[x]!=x) p[x]=find(p[x]);
    return p[x];
}
void merge(int a,int b)
{
    int pa=find(a);
    int pb=find(b);
    p[pa]=pb;
}
void Kruskal()
{
    fore(i,1,n) p[i]=i;
    sort(edges.begin(),edges.end());
    for(auto edge:edges)
    {
        int a=edge.se.fi;
        int b=edge.se.se;
        int pa=find(a);
        int pb=find(b);
        if(pa!=pb)
        {
            //record edge
            merge(a,b);
        }
    }
    
}
View Code

 

posted @ 2022-09-13 09:54  80k  阅读(47)  评论(0编辑  收藏  举报