最小生成树

最小生成树(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();
}
相关推荐
淀粉肠kk2 小时前
【C++】C++11 Lambda表达式
开发语言·c++
南境十里·墨染春水2 小时前
CMake核心用法(贴合C++编译场景)
开发语言·c++
liuyao_xianhui2 小时前
优选算法_栈_删除字符中的所有相邻重复项_C++
开发语言·数据结构·c++·python·算法·leetcode·链表
STLearner2 小时前
AI论文速读 | 元认知监控赋能深度搜索:认知神经科学启发的分层优化框架
大数据·论文阅读·人工智能·python·深度学习·学习·机器学习
老虎06272 小时前
LeetCode热题100 刷题笔记(第三天)链表 「两数相加」
笔记·leetcode·链表
WolfGang0073212 小时前
代码随想录算法训练营 Day22 | 回溯算法 part04
数据结构·算法
tankeven2 小时前
HJ154 kotori和素因子
c++·算法
!停2 小时前
C++入门基础—类和对象3
java·数据库·c++
Shirley~~2 小时前
力扣hot100:相交链表
前端·算法