053.最小生成树

最小生成树的特征

  • 无向带权图

  • n 个节点, n-1 条边

  • 所有节点连通

  • 边权和最小

  • 最小生成树一定是最小瓶颈树

  • 最小生成树可能不止一棵

模板

luogu P3366

kruskal

  • 对边排序

  • 并查集避免成环(并查集记得初始化)

  • n-1 条边

  • O(n+m)+O(m*logm)

const int N=1e5+5;
const int M=1e5+5;

struct edge{
    int u,v,w;
}e[M];
int fa[N];
void built(int n){
    for(int i=1;i<n;++i){
        fa[i]=i;
    }
}
int find(int x){
    if(fa[x]!=x){
        fa[x]=find(fa[x]);
    }
    return fa[x];
}
bool merge(int a,int b){
    int A=find(a);
    int B=find(b);
    if(A==B)return 0;
    fa[A]=B;
    return 1;
}

int kruskal(int n,int m){
    sort(e,e+m,[&](auto a,auto b){return a.w<b.w;});
    int sum=0;
    int cnt=0;
    built(n);
    for(int i=0;i<m;++i){
        if(merge(e[i].u,e[i].v)){
            sum+=e[i].w;
            cnt++;
        }
    }
    return cnt==n-1?sum:-1;
}

void solve(){
    int n,m;
    cin>>n>>m;
    for(int i=0;i<m;++i){
        cin>>e[i].u>>e[i].v>>e[i].w;
    }
    int ans=kruskal(n,m);
}

prim

  • 小根堆存边

  • vis[] 避免成环

  • n-1 条边

  • O(n+m)+O(m*logm)

const int N=1e5+5;
int vis[N];
struct edge{
    int to,cost;
};
vector<edge>gra[N];

int prim(int n){
    auto cmp=[](edge a,edge b){return a.cost>b.cost;};
    priority_queue<edge,vector<edge>,decltype(cmp)>pq(cmp);
    vis[1]=1;
    for(auto edge:gra[1]){
        pq.push(edge);
    }
    int sum=0;
    int cnt=0;
    while(pq.size()){
        auto e=pq.top();
        pq.pop();
        if(!vis[e.to]){
            vis[e.to]=1;
            sum+=e.cost;
            cnt++;
            for(auto nex:gra[e.to]){
                pq.push(nex);
            }
        }
    }
    return (cnt==n-1)?sum:-1;
}

void solve(){
   int n,m,u,v,w;
   cin>>n>>m;
   for(int i=1;i<=n;++i){
    vis[i]=0;
   }
   for(int i=0;i<m;++i){
    cin>>u>>v>>w;
    gra[u].push_back({v,w});
    gra[v].push_back({u,w});
   }
   int ans=prim(n);
}

prim堆优化版

  • 手写优化堆

  • 堆里的元素数量不会超过节点总数

  • 来到当前边,更新堆里边的信息

  • O(n+m)+O((m+n)*logn)

const int N=5005;
const int M=400005;

int n,m;
int u,v,w;

int head[N];
int nex[M];
int to[M];
int weight[M];
int tot;

int heap[N][2];
int tag[N];
int siz;
int cnt;

void built(){
    tot=1;
    siz=0;
    cnt=0;
    for(int i=1;i<=n;++i){
        head[i]=0;
        tag[i]=-1;
    }
}
void addEdge(int u,int v,int w){
    nex[tot]=head[u];
    to[tot]=v;
    weight[tot]=w;
    head[u]=tot++;
}
void swap(int i,int j){
    int a=heap[i][0];
    int b=heap[j][0];
    tag[a]=j;
    tag[b]=i;
    int t0=heap[i][0];
    heap[i][0]=heap[j][0];
    heap[j][0]=t0;
    int t1=heap[i][1];
    heap[i][1]=heap[j][1];
    heap[j][1]=t1;
}
void swim(int i){
    while(heap[i][1]<heap[(i-1)/2][1]){
        swap(i,(i-1)/2);
        i=(i-1)/2;
    }
}
void sink(int i){
    int l=2*i+1;
    while(l<siz){
        int best=l+1<siz&&heap[l+1][1]<heap[l][1]?l+1:l;
        if(heap[best][1]>=heap[i][1])return;
        swap(i,best);
        i=best;
        l=2*i+1;
    }
}
void pop(){
    u=heap[0][0];
    w=heap[0][1];
    swap(0,--siz);
    sink(0);
    tag[u]=-2;
    cnt++;
}
void update(int e){
    int v=to[e];
    int w=weight[e];
    if(tag[v]==-1){
        heap[siz][0]=v;
        heap[siz][1]=w;
        tag[v]=siz++;
        swim(tag[v]);
    }
    else if(tag[v]!=-2){
        heap[tag[v]][1]=min(w,heap[tag[v]][1]);
        swim(tag[v]);
    }
}
int prim(){
    cnt=1;
    tag[1]=-2;
    for(int e=head[1];e;e=nex[e]){
        update(e);
    }
    int ans=0;
    while(siz){
        pop();
        ans+=w;
        for(int e=head[u];e;e=nex[e]){
            update(e);
        }
    }
    return ans;
}

void solve(){
    cin>>n>>m;
    built();
    for(int i=0;i<m;++i){
        cin>>u>>v>>w;
        addEdge(u,v,w);
        addEdge(v,u,w);
    }
    int ans=prim();
    if(cnt==n)cout<<ans;
    else cout<<"orz";
}

习题

luogu P2230

const int N=305;
const int M=8005;
struct edge{
    int u,v,w;
}e[M];
int fa[N];
void built(int n){
    for(int i=1;i<n;++i){
        fa[i]=i;
    }
}
int find(int x){
    if(fa[x]!=x){
        fa[x]=find(fa[x]);
    }
    return fa[x];
}
bool merge(int a,int b){
    int A=find(a);
    int B=find(b);
    if(A==B)return 0;
    fa[A]=B;
    return 1;
}
int kruskal(int n,int m){
    sort(e,e+m,[&](auto a,auto b){return a.w<b.w;});
    int ans=0;
    built(n);
    for(int i=0;i<m;++i){
        if(merge(e[i].u,e[i].v)){
            ans=max(ans,e[i].w);
        }
    }
    return ans;
}
void solve(){
    int n,m;
    cin>>n>>m;
    for(int i=0;i<m;++i){
        cin>>e[i].u>>e[i].v>>e[i].w;
    }
    int ans=kruskal(n,m);
    cout<<n-1<<' '<<ans;
}

luogu P1550

const int N=305;
struct edge{
    int u,v,w;
}e[N*N];
int fa[N];
int find(int x){
    if(x!=fa[x]){
        fa[x]=find(fa[x]);
    }
    return fa[x];
}
bool merge(int a,int b){
    int A=find(a);
    int B=find(b);
    if(A==B)return 0;
    fa[A]=B;
    return 1;
}
void solve(){
    int n,v,tot=0;
    cin>>n;
    for(int i=0;i<n;++i){
        cin>>v;
        e[tot++]={i,n,v};
    }
    for(int i=0;i<n;++i){
        for(int j=0;j<n;++j){
            cin>>v;
            e[tot++]={i,j,v};
        }
    }
    sort(e,e+tot,[&](auto a,auto b){return a.w<b.w;});
    for(int i=0;i<=n;++i){
        fa[i]=i;
    }
    int ans=0;
    for(int i=0;i<tot;++i){
        if(merge(e[i].u,e[i].v)){
            ans+=e[i].w;
        }
    }
    cout<<ans;
}

leetcode 1584

class Solution {
    struct edge{
        int u,v,w;
    };
    int dis(int i,int j,vector<vector<int>>& p){
        return abs(p[i][0]-p[j][0])+abs(p[i][1]-p[j][1]);
    }
    vector<int>fa;
    void built(int n){
        fa.resize(n);
        for(int i=0;i<n;++i){
            fa[i]=i;
        }
    }
    int find(int x){
        if(x!=fa[x]){
            fa[x]=find(fa[x]);
        }
        return fa[x];
    }
    bool merge(int a,int b){
        int A=find(a);
        int B=find(b);
        if(A==B)return 0;
        fa[A]=B;
        return 1;
    }
public:
    int minCostConnectPoints(vector<vector<int>>& points) {
        int n=points.size();
        built(n);
        vector<edge>e;
        for(int i=0;i+1<n;++i){
            for(int j=i+1;j<n;++j){
                e.push_back({i,j,dis(i,j,points)});
            }
        }
        sort(e.begin(),e.end(),[&](auto a,auto b){return a.w<b.w;});
        int ans=0;
        for(auto x:e){
            if(merge(x.u,x.v)){
                ans+=x.w;
            }
        }
        return ans;
    }
};
posted @ 2026-01-19 21:13  射杀百头  阅读(0)  评论(0)    收藏  举报