前言:
本系列是学习了董晓老师所讲的知识点做的笔记
董晓算法的个人空间-董晓算法个人主页-哔哩哔哩视频 (bilibili.com)
动态规划系列(还没学完)
【董晓算法】动态规划之线性DP问题-CSDN博客
【董晓算法】动态规划之背包DP问题(2024.5.11)-CSDN博客
【董晓算法】动态规划之背包DP与树形DP-CSDN博客
字符串系列()
【董晓算法】竞赛常用知识之字符串1-CSDN博客
【董晓算法】竞赛常用知识之字符串2-CSDN博客
数据结构系列(未学完)
【董晓算法】竞赛常用知识点之数据结构1-CSDN博客
搜索系列
[董晓算法]搜索相关题目及模板-CSDN博客
图论系列
【董晓算法】算法知识之图论1(拓扑排序,多种最短路算法)-CSDN博客
无向图的最小环问题
Floyd 算法求最小环
1.Floyd 算法有一个性质:在最外层循环到点k时(尚未开始k次循环)dij表示的是从i到j且仅经过编号1~k-第k次循环)的点的最短路(即途经编号之k点的最短路尚未计算)
2.设最小环中编号最大的顶点为k,环上与k相邻的两个点为i,j,则在最外层循环枚举到k时,该环的长度为ans=dij+wik+wki。
3.故在循环时对于每个k枚举满足i<k且j<k 的点对(i,j)优选答案即可。
  cin>>n>>m;
  for(int i=1;i<=n;i++)
    for(int j=1;j<=n;j++)
      if(i!=j) w[i][j]=1e8;
  for(int i=1;i<=m;i++){
    cin>>a>>b>>c;
    w[a][b]=w[b][a]=c;
  }
  memcpy(d,w,sizeof d);
  for(int k=1; k<=n; k++){
    for(int i=1; i<k; i++)
      for(int j=i+1; j<k; j++)
        ans=min(ans,d[i][j]+w[j][k]+w[k][i]);
    for(int i=1; i<=n; i++)
      for(int j=1; j<=n; j++)
        d[i][j]=min(d[i][j],d[i][k]+d[k][j]);
  }最小生成树
Prim 算法
Prim(普里姆)算法基于贪心思想的最小生成树(MST) 算法
e[u]存u点的所有邻边的终点和边权。
d[u]存u点与圈外邻点的最小距离,vis[u] 标记u点是否出圈。
算法流程类似 Dikstra 算法,不断选距离最小的点出圈,直到圈内为空
1.初始化,所有点都在圈(集合)内vis=0,d[s]=0,d[其它点]=+无穷。
2.每次从圈内选取一个距离最小的点 u,打标记移出圈。
3.对u的所有邻点的距离执行更新操作
4.重复2.3步操作,直到圈内为空。
struct edge{int v,w;};
vector<edge> e[N];
int d[N], vis[N];
bool prim(int s){
  for(int i=0;i<=n;i++)d[i]=inf;
  d[s]=0;
  for(int i=1;i<=n;i++){
    int u=0;
    for(int j=1;j<=n;j++)
      if(!vis[j]&&d[j]<d[u]) u=j;
    vis[u]=1; 
    ans+=d[u];
    if(d[u]!=inf) cnt++;
    for(auto ed : e[u]){
      int v=ed.v, w=ed.w;
      if(d[v]>w) d[v]=w;
    }
  }
  return cnt==n;
}
int main(){
  cin>>n>>m;
  for(int i=0; i<m; i++){
    cin>>a>>b>>c;
    e[a].push_back({b,c});
    e[b].push_back({a,c});
  }Kruskal(克鲁斯卡尔)算法
Kruskal(克鲁斯卡尔)算法利用并查集求最小生成树(MST)
e[i] 存第i条边的起点、终点与边权
fa[x] 存x点的父节点。
1.初始化并查集,把n个点放在几个独立的集合
2.将所有的边按边权从小到大排序(贪心思想)。3.按顺序枚举每一条边,如果这条边连接的两个点不在同一集合就把这条边加入最小生成树,并且合并这两个集合;如果这条边连接的两个点在同一集合一就跳过。
4.重复执行3,直到选取了 n-1条边为止
truct edge{
  int u,v,w;
  bool operator<(const edge &t)const
  {return w < t.w;}   
}e[N];
int fa[N],ans,cnt;
int find(int x){
  if(fa[x]==x) return x;
  return fa[x]=find(fa[x]);
}
bool kruskal(){
  sort(e,e+m);
  for(int i=1;i<=n;i++)fa[i]=i;
  for(int i=0; i<m; i++){
    int x=find(e[i].u);
    int y=find(e[i].v);
    if(x!=y){
      fa[x]=y;
      ans+=e[i].w;
      cnt++;
    }
  } 
  return cnt==n-1;
}对比



















