最小生成树

最小生成树(Minimal Spanning Tree,MST)

包含图中n个点和边权和最小的n-1条边 的一棵树

Kruskal------ O ( m l o g 2 m ) O(mlog_2m) O(mlog2m)

默认n点数m边数

  • 对从短到长把边 ( u , v ) (u,v) (u,v)放入树中
  • 并查集判圈, u u u作为 v v v的父亲
    如果两点已经在一个并查集中,说明这条边会和之前放入的边形成圈,不放入

模板

cpp 复制代码
const int N = 5e3+10,M=1050;
const double PI=acos(-1);
const long long mod =998244353, inf = 1e18 ;
struct edge
{
  int u,v,w;
};
int n,m;
int fa[N];
vector<edge>e;
int find(int x){
  return fa[x]=(fa[x]==x?x:find(fa[x]));
}
void kruskal(){
  forr(i,1,n)fa[i]=i;
  sort(e.begin(),e.end(),[&](edge x,edge y){
    return x.w<y.w;
  });
  int ans=0,cnt=0;// 长度和 边数<=n-1
  for(auto [u,v,w]:e){
    if(cnt==n-1)break;
    int fu=find(u),fv=find(v);
    if(fu==fv)continue;
    else {// 放入边
      fa[fv]=fu;
      ans+=w;
      cnt++;
    }
  }
  if(cnt==n-1)cout<<ans<<endl;// 能联通所有点
  else cout<<"orz"<<endl;//不连通
}
void solve(){ 
  cin>>n>>m;
  
  forr(i,1,m){
    int x,y,z;
    cin>>x>>y>>z;
    e.push_back({x,y,z});
  }
  kruskal();
}

Prim算法------ O ( m l o g 2 n ) O(mlog_2n) O(mlog2n)

类似Dijkstra 维护一个已加入树的点集 U U U 每次向外拓展一个离点集最近的点

模板

cpp 复制代码
const int N = 5e3+10,M=1050;
const double PI=acos(-1);
const long long mod =998244353, inf = 1e18 ;
int n,m;
vector<pii>e[N];
void prim(){
  int ans=0,cnt=0;
  vector<int>U(n+1,0);
  int bg=1;
  priority_queue<pii>q;
  q.push({0,bg});
  while (q.size())
  {
    auto [dis,now]=q.top();q.pop();
    if(U[now])continue;
    U[now]=1;
    ans+=-dis;
    cnt++;
    for(auto [x,w]:e[now]){
      if(U[x])continue;
      q.push({-w,x});
    }
  }
  
  if(cnt==n)cout<<ans<<endl;
  else cout<<"orz"<<endl;
}
void solve(){ 
  cin>>n>>m;
  
  forr(i,1,m){
    int x,y,z;
    cin>>x>>y>>z;
    e[x].push_back({y,z});
    e[y].push_back({x,z});
  }
  
  prim();
}

例题

蓝桥杯省A 吊坠 最大生成树+环变链 线性dp找最长公共子串

cpp 复制代码
const int N = 205,M=1050;
const double PI=acos(-1);
const long long mod =998244353, inf = 1e18 ;
int n,m;
string s[N];
int find_w(int x,int y){
  vector<vint>dp(2*m+1,vint(2*m+1,0));
  int res=0;
  forr(i,1,2*m){
    forr(j,1,2*m){
      if(s[x][i-1]==s[y][j-1]){
        dp[i][j]=min(dp[i-1][j-1]+1,m);
        res=max(dp[i][j],res);
      }// 注意是子串 子串是连续的
    }
  }
  return res;
}
struct edge
{
  int u,v,w;
};
vector<edge>e;
int fa[N];
int find(int x){
  return fa[x]=(fa[x]==x?x:find(fa[x]));
}
void kruskal(){
  forr(i,1,n)fa[i]=i;
  sort(e.begin(),e.end(),[&](edge x,edge y){
    return x.w>y.w;
  });
  int ans=0,cnt=0;
  for(auto [u,v,w]:e){
    if(cnt==n-1)break;
    int fu=find(u),fv=find(v);
    if(fu==fv)continue;
    fa[fv]=fu;
    cnt++;
    ans+=w;
  }
  cout<<ans<<endl;
}
void solve(){ 
  cin>>n>>m;
  forr(i,1,n){
    cin>>s[i];
    s[i]+=s[i];
  }
  forr(i,1,n){
    forr(j,i+1,n){
      int w=find_w(i,j);
      
      e.push_back({i,j,w});
    }
  }
  kruskal();
}
相关推荐
LinXunFeng4 小时前
Obsidian - 使用 Share Note 分享笔记并自部署
前端·笔记·github
JieE2121 天前
LeetCode 101. 对称二叉树|JS 递归 + 迭代双解法,彻底搞懂镜像判断
javascript·算法
JieE2122 天前
LeetCode 56. 合并区间|超清晰 JS 图解思路,面试高频区间题
javascript·算法·面试
Jack202 天前
HarmonyOS开发中错误处理策略:网络异常统一处理
算法
小小杨树3 天前
读懂色彩:拍照调色不再难
算法·计算机视觉·配色
JieE2123 天前
LeetCode 226. 翻转二叉树|JS 递归超详细拆解,二叉树入门经典题
javascript·算法
JieE2123 天前
LeetCode 104. 二叉树的最大深度|递归思路超详细拆解
javascript·算法
vivo互联网技术3 天前
CVPR 2026 | 全新强化学习框架 BeautyGRPO:重塑真实人像
算法·大模型·cvpr·影像
Darling噜啦啦3 天前
列表转树算法深度解析:从 Map 到 Reduce 的两种实现,面试高频考点
数据结构·算法·面试