最小生成树

假设 \(n\) 表示图中点数,\(m\) 表示图中边数。

Prim算法堆优化

时间复杂度 \(O(nlogn)\)

核心思想:每次挑一条与当前集合相连的最短边。

code

int ans,cnt;
struct edge{int v,w;};
vector<edge> e[N];
int d[N], vis[N];
priority_queue<pair<int,int>> q;
        
bool prim(int s){
  for(int i=0;i<=n;i++) d[i]=inf;
  d[s]=0; q.push({0,s});
  while(q.size()){
    int u=q.top().second; q.pop();
    if(vis[u])continue;//再出队跳过
    vis[u]=1;//标记u已出队
    ans+=d[u]; cnt++;
    for(auto ed : e[u]){
      int v=ed.v, w=ed.w;
      if(d[v]>w){
        d[v]=w;
        q.push({-d[v],v});//大根堆
      }
    }
  }
  return cnt==n;
}

Kruskal算法

适用于稀疏图,时间复杂度 \(O(mlogm)\)

核心思想:从小到大挑不多余的边。

C++ 代码

#include <bits/stdc++.h>
using namespace std;

const int N=200006;
int n, m;
int ans=0;
struct edge{
  int u,v,w;
  bool operator<(const edge &t)const
  {return w < t.w;}   
}e[N];//结构体存边
struct DSU {
  vector<int> f, siz;
    
    DSU() {}
    DSU(int n) {
        init(n);
    }
    
    void init(int n) {
        f.resize(n);
        std::iota(f.begin(), f.end(), 0);
        siz.assign(n, 1);
    }
    
    int find(int x) {
        while (x != f[x]) {
            x = f[x] = f[f[x]];
        }
        return x;
    }
    bool same(int x, int y) {
        return find(x) == find(y);
    }
    
    bool merge(int x, int y) {
        x = find(x);
        y = find(y);
        if (x == y) {
            return false;
        }
        siz[x] += siz[y];
        f[y] = x;
        return true;
    }
    
    int size(int x) {
        return siz[find(x)];
    }
};
bool kruskal(){//返回的是原图的连通性,最小生成树的答案并没有返回,注意自己处理。
  sort(e+1,e+m+1);
 DSU dsu(n+1);
 int cnt=0;
  for(int i=1; i<=m; i++){
     int x=(e[i].u);
     int y=(e[i].v);
    if(!dsu.same(x,y))
   {
      dsu.merge(x,y);
      ans+=e[i].w;
      cnt++;
    }
  } 
  return cnt==n-1;
}
int main(){
  cin>>n>>m;
  for(int i=1; i<=m; i++)
    cin>>e[i].u>>e[i].v>>e[i].w;
  if(!kruskal()) puts("impossible");
  else printf("%d\n",ans);
  return 0;
}
posted @ 2023-12-08 22:20  potential-star  阅读(6)  评论(0编辑  收藏  举报