最小树形图 朱刘算法

最小树形图 之 朱刘算法【模板】 定义:一个有向图,存在从某个点为根的,可以到达所有点的一个最小生成树,则它就是最小树形图。 朱刘算法实现过程: 【在选出入边集后(看步骤1),若有向图中不存在有向环,说明该图就是最小树形图】 1,选入边集——找到除root点之外,每一个点的所有入边中权值最小的,用数组in[]记录下这个最小权值,用pre[]记录到达该点的前驱;(若图中存在独立点,最小树形图是不存在的,所 阅读详情

  最小树形图,就是给有向带权图中指定一个特殊的点root,求一棵以root为根的有向生成树T,并且T中所有边的总权值最小。也就是有向图的最小生成树。

  1.找到除了root外的到每个点u权值最小的一条边,记为iw[u]。

  2.如果存在除了root之外的孤立点,则不存在最小树形图。

  3.如果有环,就把环缩成一个点,把所有环都缩点后对所有点重新编号。

  4.更新其它点到环的距离,比如本来到还上v点的边,权值就减去iw[v]。

  重复这个过程直到没有环。

  第4步的原因是当前答案加上了这个环的权值,但是如果最后图里有到v的那条边,环上iw[v]这条边并不需要,可以删掉了,删掉也是生成树。所以把到v的边权值减去iw[v],最后加上这个权值也就相当于删掉了边iw[v]的权值。


网上的图


 

  LRJ的邻接矩阵写法。

// 固定根的最小树型图,邻接矩阵写法
struct MDST {
  int n;
  int w[maxn][maxn]; // 边权
  int vis[maxn];     // 访问标记,仅用来判断无解
  int ans;           // 计算答案
  int removed[maxn]; // 每个点是否被删除
  int cid[maxn];     // 所在圈编号
  int pre[maxn];     // 最小入边的起点
  int iw[maxn];      // 最小入边的权值
  int max_cid;       // 最大圈编号

  void init(int n) {
    this->n = n;
    for(int i = 0; i < n; i++)
      for(int j = 0; j < n; j++) w[i][j] = INF;
  }

  void AddEdge(int u, int v, int cost) {
    w[u][v] = min(w[u][v], cost); // 重边取权最小的
  }

  // 从s出发能到达多少个结点
  int dfs(int s) {
    vis[s] = 1;
    int ans = 1;
    for(int i = 0; i < n; i++)
      if(!vis[i] && w[s][i] < INF) ans += dfs(i);
    return ans;
  }

  // 从u出发沿着pre指针找圈
  bool cycle(int u) {
    max_cid++;
    int v = u;
    while(cid[v] != max_cid) { cid[v] = max_cid; v = pre[v]; }
    return v == u;
  }

  // 计算u的最小入弧,入弧起点不得在圈c中
  void update(int u) {
    iw[u] = INF;
    for(int i = 0; i < n; i++)
      if(!removed[i] && w[i][u] < iw[u]) {
        iw[u] = w[i][u];
        pre[u] = i;
      }
  }

  // 根结点为s,如果失败则返回false
  bool solve(int s) {    
    memset(vis, 0, sizeof(vis));
    if(dfs(s) != n) return false;

    memset(removed, 0, sizeof(removed));
    memset(cid, 0, sizeof(cid));
    for(int u = 0; u < n; u++) update(u);
    pre[s] = s; iw[s] = 0; // 根结点特殊处理
    ans = max_cid = 0;
    for(;;) {
      bool have_cycle = false;
      for(int u = 0; u < n; u++) if(u != s && !removed[u] && cycle(u)){
        have_cycle = true;
        // 以下代码缩圈,圈上除了u之外的结点均删除
        int v = u;
        do {
          if(v != u) removed[v] = 1;
          ans += iw[v];
          // 对于圈外点i,把边i->v改成i->u(并调整权值);v->i改为u->i
          // 注意圈上可能还有一个v'使得i->v'或者v'->i存在,因此只保留权值最小的i->u和u->i
          for(int i = 0; i < n; i++) if(cid[i] != cid[u] && !removed[i]) {
            if(w[i][v] < INF) w[i][u] = min(w[i][u], w[i][v]-iw[v]);
            w[u][i] = min(w[u][i], w[v][i]);
            if(pre[i] == v) pre[i] = u;
          }
          v = pre[v];
        } while(v != u);        
        update(u);
        break;
      }
      if(!have_cycle) break;
    }
    for(int i = 0; i < n; i++)
      if(!removed[i]) ans += iw[i];
    return true;
  }
};

邻接表写法

struct Edge{
    int u,v,w;
}e[MAXM];

bool MDST(int s,int n,int m){
    ans=0;
    while(1){
        //计算iw
        for(int i=0;i<n;i++) iw[i]=INF;
        for(int i=0;i<m;i++){
            int u=e[i].u,v=e[i].v;
            if(u!=v&&e[i].w<iw[v]){
                iw[v]=e[i].w;
                pre[v]=u;
            }
        }
        //如果存在孤立点,则不存在最小树形图
        for(int i=0;i<n;i++) if(i!=s&&iw[i]==INF){
            return false;
        }
        int cid=0;  //环的编号
        iw[s]=0;    //root节点特殊处理,iw=0
        memset(vis,-1,sizeof(vis));
        memset(cir,-1,sizeof(cir));
        for(int i=0;i<n;i++){
            ans+=iw[i];
            //判断环
            int v=i;
            while(vis[v]!=i&&cir[v]==-1&&v!=s){
                vis[v]=i;
                v=pre[v];
            }
            //存在环,把环上的点编成一个号
            if(vis[v]==i){
                for(int u=pre[v];u!=v;u=pre[u]) cir[u]=cid;
                cir[v]=cid++;
            }
        }
        if(!cid) return true;//不存在环,得到最小树形图
        //把剩下的点也重新编号
        for(int i=0;i<n;i++) if(cir[i]==-1){
            cir[i]=cid++;
        }
        //更新其它节点到环的距离
        for(int i=0;i<m;i++){
            int u=e[i].u,v=e[i].v;
            e[i].u=cir[u];
            e[i].v=cir[v];
            if(e[i].u!=e[i].v) e[i].w-=iw[v];
        }
        //新的节点数和root编号
        n=cid;
        s=cir[s];
    }
}


poj 3164 && tju 2248 最小树形图 朱刘算法 个人觉得这个博客把这个算法说的比较详细了,直接搬过来吧,我再阐述一遍的话没有人家说的好,还容易说错。 ========================== 分割线之下摘自Sasuke_SCUT的blog====================================== 阅读详情

相关推荐

从零到一:海外短剧成品系统源码搭建流程详解及APP+H5交付服务

在当今全球化的数字娱乐浪潮中,海外短剧市场以其独特的文化魅力和广阔的受众基础,正逐渐成为内容创作者与平台运营者争相布局的新蓝海。我为了紧跟时代的发展我翻看了大量的文章,偶然间看到了一篇文章点进去发现他们是专业做短剧开发的,总结下来在这篇文章里分享给大家。

liangyill_的博客 907

最小树形图-朱刘算法详解 +例题解析

文章目录最小树形图定义和最小生成树的区别朱刘算法思想步骤流程展示算法实现例题 最小树形图 定义 对于有向图G=(V,E)G = (V,E)G=(V,E),其中具有如下性质 GGG中不包含有向环。 存在一个根结点uuu,它不是任何弧的终点,而且uuu的其他顶点都恰好是唯一的一条弧的终点。 那么则称GGG是以uuu为根的树形图。 更笼统的讲,实际上就是有一颗不存在有向环的有向树,且除根结点uuu外的每个顶点都只有一条入边。 而最小树形图则是权值最小的那个。 这是一个最小树形图的例子。 和最小生成树的区别

pursuit的博客 8266

使用网分对晶体ESR/L1/C1/C0进行测量计算

Use R&amp;S Vector Network Analyzer test XTAL ESR/L1/C1/C0 測量方法:使用儀器的Port1端口,測量XTAL的S11,通過諧振的參數計算出ESR/L1/C1/C0的值。 實際晶體的等效模型:通常方便晶體分析,使用下圖(b)的等效模型,但實際測量發現晶體存在多個串聯諧振點,實際等效模型更接近(c)。 儀器測量到的S11,其中M...

qq_39138630的博客 2082

最小树形图(朱-刘算法)

概念导入:最小树形图可以简单的理解为树枝有方向的最小生成树,加上了方向的限制,使得得到它要稍微麻烦一点,解决这个问题的算法是朱永津与刘振宏在上世纪60年代提出的朱-刘算法(难得的中国人的算法)。 定义:设G = (V,E)是一个有向图,它具有下述性质: 1. G中不包含有向环;  2. 存在一个顶点vi,它不是任何弧的终点,而V中的其它顶点都恰好是唯一的一条弧的终点; 则...

Izayoi_w的博客 1023

Raspberry Pi Pico SDK开发-Timer-定时

RP2040 由 Raspberry Pi 设计,具有双核 Arm Cortex-M0+ 处理器和 264KB 内部 RAM,并支持高达 16MB 的片外闪存。 广泛的灵活 I/O 选项包括 I2C、SPI 和独特的可编程 I/O (PIO)。 本实例将演示如何使用Timer的定时功能。

视觉与物联智能 2040

XDMA原理学习(1)——DMA技术详解

DMA 技术是Direct Memory Access的缩写,其意思是“存储器直接访问”。它是指一种高速的数据传输操作,允许在外部设备和存储器之间直接读写数据,既不通过CPU,也不需要CPU干预。DMA是所有现代计算机的重要特色,它允许不同速度的硬件设备进行沟通,而不需要依于中央处理器的大量中断负载。否则,中央处理器需要从来源把每一片段的数据复制到寄存器,然后把它们再次写回到新的地方。在这个时间里,中央处理器就无法执行其它的任务。

apple_53311083的博客 8377

【算法精讲】最小树形图 (两份讲解 配套例题)

其一 概述 最小树形图, 简而言之就是求有向带权图的最小生成树. 官方定义是这样的: 最小树形图,就是给有向带权图中指定一个特殊的点root,求一棵以root为根的有向生成树T,并且T中所有边的总权值最小。 通解最小树形图的一种算法是是1965年朱永津和刘振宏提出的复杂度为O(VE)的算法:朱、刘算法。 今天我们就来浅谈一下最小树形图的问题。 最小树形图, 简而言之就是求有向带权图的最小生成树....

Suprit's blog 2246

还在纠结二层交换机和三层交换机的区别?这篇文章帮你讲明白!

你好,这里是网络技术联盟站,我是瑞哥。公众号后台有小伙伴想要写一篇文章具体介绍一下二层交换机和三层交换机,此类的文章,之前写过几篇,今天瑞哥再写一篇,希望对大家有所帮助!

网络技术联盟站 4438

最小树形图——朱刘算法

一、相关定义 定义:设G = (V,E)是一个有向图,它具有下述性质: G中不包含有向环;  存在一个顶点vi,它不是任何弧的终点,而V中的其它顶点都恰好是唯一的一条弧的终点,则称 G是以vi为根的树形图。 最小树形图就是有向图G = (V, E)中以vi为根的树形图中权值和最小的那一个。 另一种说法:最小树形图,就是给有向带权图一个特殊的点root,求一棵以root为根节点的树使得该树的...

Baiyi_destroyer的博客 691

MIKE水动力笔记7_实测数据与模型输出结果的拟合对比

上一博文【MIKE水动力笔记6】主要讲解如何自己制作实测数据的时间序列文件dfs0,而本博文讲解如何进行实测数据与模型输出结果的拟合对比。

晏长街的博客 1万+

基于Simulink的MIMO-OFDM系统仿真建模示例

MIMO概述MIMO技术利用多个天线进行信号发送和接收,通过空间复用来提高数据传输速率,或通过空间分集来增强信号的可靠性。OFDM概述OFDM是一种将高速率数据流分成多个低速数据流并行传输的技术,每个子载波都采用调制方式(如BPSK、QPSK),并通过IFFT/FFT变换实现串并转换。MIMO-OFDM优势结合了MIMO的空间分集增益与OFDM对抗多径效应的能力,适用于宽带无线通信系统。提供了更高的数据速率和更好的频谱效率,是现代无线通信标准(如4G LTE、5G NR等)的核心技术之一。

xiaoheshang_123的博客 327

图论 —— 生成树 —— 最小树形图

【概述】 最小树形图,就是给出一个带权有向图,从中指定一个特殊的结点 root,求一棵以 root 为根的有向生成树 T,且使得 T 中所有边权值最小。 简单来说,最小树形图就是有向图的最小生成树。 【朱刘算法】 1.过程 简单来说,朱刘算法分为四个过程: 1)求最短弧集合 E 2)判断集合 E 中有没有有向环,如果有转步骤 3,否则转 4 3)收缩点,把有向环收缩成一个点,并且对...

Alex_McAvoy的博客 6247

CKS-CN考试之路----03

这题不需要去生成image和生成deployment所以只需要去检测对应的值即可。编辑/cks/docker/Dockerfile,修改最后第二行的值。编辑/cks/docker/deployment.yaml。

Q先生 824

14 最小树形图&朱刘算法

最小树形图 朱刘算法

weixin_45034895的博客 1164

怀旧版电脑GBC模拟器

再现原版GBC掌机的界面,电脑运行连游戏界面都一样大小,很怀旧,很真实,(英文版)强烈推荐,很小的文件,很难才找到的。

蓝牙模块HM-10手册

蓝牙模块HM-10手册,该手册对蓝牙模块HM-10进行了详细的介绍和使用方法以及一些AT指令。

最小树形图+朱刘算法

大题上完整的朱、刘算法是由四个大步骤组成的: 1、求最短弧集合E 2、判断集合E中有没有有向环,如果有转步骤3,否则转4 3、收缩点,把有向环收缩成一个点,并且对图重新构建,包括边权值的改变和点的处理,之后再转步骤1。 4、展开收缩点,求得最小树形图。 因为我们ACM一般情况下都是在考察队最小树型图的权值问题,所以一般省略步骤4,对于其环的权值和在中间处理过程中就可以处理完毕。所以我...

日拱一卒,功不唐捐 3014

visio安装包

Microsoft Office Visio 是一款专业的制图软件。利用经过更新的形状、协作工具和数据链接图表,创建专业级图表以简化复杂的信息。

【总结】最小树形图 朱刘算法

前言 省选复习的时候,发现没写博客。。。 来补一篇。。 最小树形图 就是有向图的最小生成树,满足从根出发,能到达所有节点,且边权和尽可能小。 朱刘算法 很暴力的方法,每个点在指向它的边中,选择最小的一条(根节点不选)。 然后答案加上每个点选出的边权。 然后可能有环,就缩环成点,然后改一下边权 val’-=val,表示之后若选择val’,则必须断开val 一直这样做下去,直到某一次找不到环了就停止...

氧化钠的博客 872

android 蓝牙通讯demo

android 下蓝牙通讯demo,实现了发现蓝牙,使能蓝牙,通过蓝牙发送消息。

HDU 4009 Transfer water 最小树形图 朱刘算法

/* 很裸的朱刘算法,后悔昨天比赛前没看过朱刘算法,掩面大哭~~ 抽象一个超级起点,连改点到每个点的单向边,边权为点自身的建井的代价 如果可以从i连水管到v,建一条i到v的单项边,边权为修水管的代价 然后就是用朱刘算法求最小树形图了。朱刘算法详见:http://blog.csdn

Join Hands 3123

最小树形图模版——朱刘算法

/* 最小树形图图模版-朱刘算法 模版说明:点标号必须0-(N-1) 必须去除到自身的点(到自身的边的边权赋无限大) */ #define M 109 #define type int const type inf=(1)<<30; struct Node{ int u

Join Hands 5420

朱刘算法(最小树形图)

P4716 【模板】最小树形图 题目 题目描述 给定包含nn个结点,mm条有向边的一个图。试求一棵以结点rr为根的最小树形图,并输出最小树形图每条边的权值之和,如果没有以rr为根的最小树形图,输出-1−1。 输入格式 第一行包含三个整数n,m,rn,m,r,意义同题目所述。 接下来mm行,每行包含三个整数u,v,wu,v,w,表示图中存在一条从uu指向v...

Sun Sun day的博客 539

【图论】朱刘算法求最小树形图

以洛谷P4716为例 #include<bits/stdc++.h> #define ll long long #define IO ios::sync_with_stdio(false);cin.tie(0); using namespace std; const int M=1e6+5; const int N=1e6+5; const int inf=2e9; struct Ed...

Rainfoo的博客 350

最小树形图/朱刘算法

最小树形图/朱刘算法 最小生成树是具有最小权值的无向树,最小树形图则是具有最小权值的有向树 算法思想和kruskal类似,也是采用贪心的思想,每次取用权值最小的那条边,只是由于有向图边权带有方向,有一些特殊情况需要我们去解决。 1.是否存在最小树形图;我们知道在无向图中(不考虑负权),只要所有点都是连通的,就一定存在最小生成树,在有向图中也是一样的,每个点都必须存在一条连向它的边,即不存在某个点,它的入度为0 ,如果有某个点入度为0,那就不存在树形图(不连通),更不存在最小树形图。 2.每次取权值最小的边,

qq_52406324的博客 450

最小树形图(朱刘算法)

最小树形图: 类似最小生成树。给定有向图,求用给定边所能构成的最小树。 朱刘算法: 贪心算法。可以想到每次都找每个点的入边中最小的一个来构成树,如果构成了,就是最小的。但是构成过程中可能会出现环,这时候就需要缩点。 而且因为每个点只选取一条入边,所以构成的环一定是简单环,没有必要用tarjan求强连通分量来找缩点。这样编写难度会小很多。 每次找到环以后需要更新权值,规则是这样的:对于每条指向环的边,该边边权减去所指向点的最小入边。更新后继续找环,直到没有环,即找到最小树形图。 例题:最小树形图 #incl

Khasehemwy的博客 566

POJ--3164--Command Network【朱刘算法】最小树形图

链接:http://poj.org/problem?id=3164 题意:告诉n个点坐标,m条边表示两个点之间有路,从1点开始建立一个有向图最小生成树。 朱刘算法模板题 ========================== 分割线之下摘自Sasuke_SCUT的blog================================================== 最 小树形图,就是给

阳光照耀圣西罗 1189

生成树最小树形图 -- 朱刘算法详解

本文借鉴的博文: zephyr_pro dalao的blog 朱刘算法引入: (把一道最小树形图当作最小生成树来做了,wa了后以为是bug像个sb一样d了半天) 最小树形图和最小生成树都是要求总权值最小,但区别四一个有向、一个无向。有向的最小树形图是不能用prim 或krustra算法来求解的。why?因为prim 或krustra算法只能适用无向图的环,不能适用有向图的环。 举个例子,如图: ...

dajiangyou123456的博客 2026

最小树形图-朱刘算法 配题(Codeforces Road Repairs)

最小树形图就是一张有向图的最小生成树,可能存在也可能不存在。树形图的定义是从一个点出发可以到达任何一个点,并且除了源点的所有点的入度都为1,那么最小树形图就是所得到的所有树形图中权重总和最小的树形图,叫作最小树形图。 最小树形图的算法本文采用朱刘算法: 寻找当前图的最短弧 判断是否为树形图 判断并且标记有向环 将有向环进行收缩形成一个新的点,更新所有指向这个有向环中任何点的边权 上述步...

猫ER 647
上一篇: uva11354 - Bond 最小瓶颈路+LCA
下一篇: hdu5044 Tree 上海网络赛1003 LCA+输入输出外挂
小小小小葱
博客等级 码龄14年 22粉丝 266原创
评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

个

红包个数最小为10个

元

红包金额最低5元

当前余额3.43元 前往充值 >
需支付:10.00元
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付元
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值