最小生成树

最小生成树(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();
}
相关推荐
程与留2 分钟前
05_Qt 核心模块概览——Qt Core、Gui、Widgets、Quick 的职责划分
c++·qt
HY小宝F5 分钟前
树莓派 FFmpeg 实战笔记(二):命令行、源码编译与硬件编码的真相
学习·职场和发展·ffmpeg
树的枝12 分钟前
【STM32】03.中断和EXTI外设
笔记·stm32·单片机·嵌入式硬件
2601_9672642817 分钟前
Jetpack Compose 实践指南:从入门到进阶
java·学习
buhuizhiyuci37 分钟前
【QT-百日筑基篇】修真世界摸爬滚打多年,终于黄天不负有心人,突破炼器中期——常用控件QWight的属性
开发语言·c++·qt·gui·图形化
Wang's Blog42 分钟前
PostgreSQL笔记34:索引优化策略全景解析——从B-tree到HOT的核心原理与实践
数据库·笔记·postgresql
金字塔頂の蝸牛1 小时前
商务日语口语实用手册
笔记·学习笔记·日语·外语
小雪崩1 小时前
嵌入式学习 day25:哈希表及排序与查找
linux·c语言·数据结构·学习·排序算法
白露与泡影1 小时前
解密 Pi 的 Harness 工程:Agent 会话如何实现持久化与恢复
java·人工智能·算法
HwJack202 小时前
UIAbility 生命周期全链路:从冷启动到热启动的实战笔记
笔记·华为·harmonyos