首页 > 其他分享 >最小生成树

最小生成树

时间:2023-01-25 10:56:15浏览次数:51  
标签:标记 int 最小 bian 生成 length dis

最小生成树

定义

生成树:一张n个点的连通图中,选择n-1条边与n个点组成的树

最小生成树:即生成树中边权之和的最小者(可能存在多棵)

P3366 【模板】最小生成树

Prim算法 O(mlogm)

与Dijkstra非常类似

  1. 将1号点放入生成树中并标记,同时更新与它相连的点的dis值
  2. 选择未标记的点中dis最小的点,加入生成树中并标记
  3. 使用与该点的连边更新相连点的dis
  4. 重复2,3步,直到所有的点都被标记或所有未标记的点都无连边与已标记的点直接相连

所以,当标记的点的数量<点的总数量时,图不联通,无解

直接放代

#include<bits/stdc++.h>
using namespace std;
int inf=99999999999;
struct P{
	int dis,id;
    bool operator < (const  &that) const{
        return dis>that.dis;
    }
};//用优先队列来优化
struct node{
	int to,next,length;
}bian[200010];
int dis[5001],head[200010],k;
bool vis[5001];
void add(int u,int v,int w){
    bian[++k].to=v;
    bian[k].length=w;
    bian[k].next=head[u];
    head[u]=k;
}
int n,m,ans;
priority_queue<P> q;
int tot;//用来记录标记的点的数量
void prim(){
    for(int i=1;i<=n;i++)dis[i]=inf;
    dis[1]=0;
    q.push((P){0,1});
    while(!q.empty()){
        int u=q.top().id;
        q.pop();
        if(vis[u])continue;
        vis[u]=1;
        tot++;
        ans+=dis[u];
        for(int i=head[u];i;i=bian[i].next){
            int v=bian[i].to;
            if(dis[v]>bian[i].length){
                dis[v]=bian[i].length;
                q.push((P){dis[v],v});
            }
        }
    }
}
int main(){
    cin>>n>>m;
    for(int i=1;i<=m;i++){
        int a,b,c;
        cin>>a>>b>>c;
        add(a,b,c);
        add(b,a,c);
    }
    prim();
    if(tot==n)cout<<ans;
    else cout<<"orz";
    return 0;
}

Prim与Dijkstra求最短路的区别:

注意到代码的第38行

修改dis值,是保存它与其他点的连边的边长最小值

而最短路则是保存与起点的最短距离

最小生成树求的是边权之和

Kruskal算法 O(mlogm)

  1. 将所有边从小到大排序
  2. 将所有点放入各自的并查集
  3. 选择所有未使用边中边权最小的
  4. 若该边所连接的两点已经联通(即成环),则舍去,否则合并这两个并查集
  5. 重复3,4步,直到所有的点都被标记或所有未标记的点都无连边与已标记的点直接相连
#include<bits/stdc++.h>
using namespace std;
struct node{
  int from.to,length;  
}bian[4000010];
int fa[10010],n,m,ans,cnt;
bool comp(node x,node y){
    return x.length<y.length;
}
int find(int x){
    if(x==fa[x])return x;
    return fa[x]=find(fa[x]);
}
void kruskal(){
    sort(bian+1,bian+m+1,comp);
    for(int i=1;i<=m;i++){
        int u=find(bian[i].from);
        int v=find(bian[i].to);
        if(u==v)continue;
        ans+=bian[i].length;
        fa[v]=u;
        cnt++;
    }
}
int main(){
    cin>>n>>m;
    for(int i=1;i<=n;i++)fa[i]=i;
    for(int i=1;i<=m;i++)cin>>bian[i].from>>bian[i].to>>bian[i].length;
    kruskal();
    if(cnt==n-1)cout<<ans;
    else cout<<"orz";
}

标签:标记,int,最小,bian,生成,length,dis
From: https://www.cnblogs.com/alwayslove/p/17066737.html

相关文章

  • LLVM目标无关代码生成器Target-Independent Code Generator
    LLVM目标无关代码生成器Target-IndependentCodeGenerator介绍LLVM目标无关代码生成器是一个框架,提供了一套可重用组件,用于将LLVM内部表示转换为指定目标的机器代码,无论......
  • nginx 做图像服务器,生成图片的URL,让前端访问
    需求:后端不断产生新的图片数据,发送给前端,前端然后显示。方案:1.后端可以生成一个图片URL地址,然后返回给前端【采用】2.或者返回base64疑问:将图片文件......
  • 刷刷刷 Day 21 | 530. 二叉搜索树的最小绝对差
    530.二叉搜索树的最小绝对差LeetCode题目要求给你一个二叉搜索树的根节点root,返回树中任意两不同节点值之间的最小差值。差值是一个正数,其数值等于两值之差的绝对......
  • 生成器与yield
    目录生成器与yieldyield表达式应用三元表达式、列表生成式、生成器表达式三元表达式列表生成式生成器表达式生成器与yield若函数体包含yield关键字,再调用函数,并不......
  • 如何生成更好地和 chatGPT 沟通
    我学到的是,要更好地和它沟通,首先要这做到三点:1️⃣给它一个角色身份,告诉它它到底是谁。2️⃣给它充分的上下文信息,告诉它你要实现什么目标,以及为什么要实现这个目标。3️⃣不要指......
  • 代码随想录 | Day2 | LC 977有序数组的平方、209长度最小的子数组
    977.有序数组的平方解法1:暴力classSolution{publicint[]sortedSquares(int[]nums){for(inti=0;i<nums.length;i++){nums[......
  • 使用Stable-Diffusion生成视频的完整教程
    本文是关于如何使用cuda和Stable-Diffusion生成视频的完整指南,将使用cuda来加速视频生成,并且可以使用Kaggle的TESLAGPU来免费执行我们的模型。完整文章:https://avoid.o......
  • 生成函数法推导自然数幂求和公式
    本文主要介绍用生成函数推导形如\(\sum_{k=1}^nk^a,a\inN^+\)的【自然数幂求和公式】的方法。之前在知乎、博客园看到各种奇奇怪怪的推导【平方和】、【立方和】等自然......
  • 生成requirements.txt文件
    对于Python项目,生成和使用requirements.txt是十分必要的。通过requirements.txt可以一次性保存和安装项目所需要的所有库。尤其是在不同电脑操作时。requirements.txt的样......
  • 最小生成树
    MST定义:一个无向图中的一棵生成树,满足其边权和最小。对于一个无向图,其不一定唯一。同时满足另外两个性质:在一棵生成树\(T\)中,任意两个点\(i,j\)的路径上最大边权记......