最小树形图(朱刘算法)
不好意思 时间比较短,下面应该还会有修订的= = , 那段话是我复制过来的,觉得挺好的就用一下.
下面是讲解(不理解一的时候 , 可以看看二 ,结合图片):
一: 最小树形图,就是给有向带权图中指定一个特殊的点root,求一棵以root为根的有向生成树T,并且T中所有边的总权值最小。最小树形图的第一个算法是 1965年朱永津和刘振宏提出的复杂度为O(VE)的算法。
判断是否存在树形图的方法很简单,只需要以v为根作一次图的遍历就可以了,所以下面的 算法中不再考虑树形图不存在的情况。
在所有操作开始之前,我们需要把图中所有的自环全都清除。很明显,自环是不可能在任何一个树形图上的。只有进 行了这步操作,总算法复杂度才真正能保证是O(VE)。
首先为除根之外的每个点选定一条入边,这条入边一定要是所有入边中最小的。现在所有的最小 入边都选择出来了,如果这个入边集不存在有向环的话,我们可以证明这个集合就是该图的最小树形图。这个证明并不是很难。如果存在有向环的话,我们就要将这 个有向环所称一个人工顶点,同时改变图中边的权。假设某点u在该环上,并设这个环中指向u的边权是in[u],那么对于每条从u出发的边(u, i, w),在新图中连接(new, i, w)的边,其中new为新加的人工顶点; 对于每条进入u的边(i, u, w),在新图中建立边(i, new, w-in[u])的边。为什么入边的权要减去in[u],这个后面会解释,在这里先给出算法的步骤。然后可以证明,新图中最小树形图的权加上旧图中被收缩 的那个环的权和,就是原图中最小树形图的权。
上面结论也不做证明了。现在依据上面的结论,说明一下为什么出边的权不变,入边的权要减去in [u]。对于新图中的最小树形图T,设指向人工节点的边为e。将人工节点展开以后,e指向了一个环。假设原先e是指向u的,这个时候我们将环上指向u的边 in[u]删除,这样就得到了原图中的一个树形图。我们会发现,如果新图中e的权w'(e)是原图中e的权w(e)减去in[u]权的话,那么在我们删除 掉in[u],并且将e恢复为原图状态的时候,这个树形图的权仍然是新图树形图的权加环的权,而这个权值正是最小树形图的权值。所以在展开节点之后,我们 得到的仍然是最小树形图。逐步展开所有的人工节点,就会得到初始图的最小树形图了。
如果实现得很聪明的话,可以达到找最小入边O(E),找环 O(V),收缩O(E),其中在找环O(V)这里需要一点技巧。这样每次收缩的复杂度是O(E),然后最多会收缩几次呢?由于我们一开始已经拿掉了所有的 自环,我门可以知道每个环至少包含2个点,收缩成1个点之后,总点数减少了至少1。当整个图收缩到只有1个点的时候,最小树形图就不不用求了。所以我们最 多只会进行V-1次的收缩,所以总得复杂度自然是O(VE)了。由此可见,如果一开始不除去自环的话,理论复杂度会和自环的数目有关。
二: 最开始的图,把所有的最小入边都累加到ret里。至于为什么,因为这样才能保证所得的ret有可能是最小树形图的解,当然,是在这些最小入边集合不行成环得情况下。
如果有了环,ret肯定不是最终答案,因为环中间有的边需要删掉,而且环之间也要连接起来。现在我们无法得知删除环中的哪些边才行。这就需要建立新图了。
举个例子:某个图的部分图中, 1->2权值为3, 2->1权值为4, 3->1权值为9, 4->2权值为7。 那么可以看到,结点1和结点2是形成了一个环的。我们仅从其大小不知道删除哪条边比较好,这时看到3->1权值为9, 如果走这条边,那么接下来只能删除掉2->1这条边,同理走4->2的话就要删除掉1->2这条边。 那么就不妨建立新图, 将1和2缩成一点,3->1的权值就变成了9-4=5, 4->2的权值变成了7-3=4。 这样的话,就相当于变相删除了不需要走的边了。形成新图后,又变成了最小树形图的求解,就这样循环下去,直到图中的最小边集没有环为止。
下面是模板代码:
1 #include <iostream> 2 #include <cstring> 3 #include <cstdio> 4 5 using namespace std; 6 const int MAXN = 1e4 , INF = 1e8; 7 int d[MAXN] , id[MAXN] , vis[MAXN] , pre[MAXN]; //d:除root点外每个点的最小入边 id:下一次建图新的节点号 vis:用来判断是否成环 下面程序见 pre:点的前序节点 8 int V , E; // V:点的个数 E:边的个数 9 struct node { 10 int u , v , cost; //边的起点 终点 以及长度 11 }edge[MAXN]; 12 13 int zhuliu(int root) { 14 int res = 0; //最小树形图的长度 15 while(true) { 16 for(int i = 0 ; i < V ; i++) { 17 d[i] = INF; 18 } 19 for(int i = 0 ; i < E ; i++) { //寻找最小入边 20 int u = edge[i].u , v = edge[i].v; 21 if(u != v && edge[i].cost < d[v]) { 22 pre[v] = u; 23 d[v] = edge[i].cost; 24 } 25 } 26 for(int i = 0 ; i < V ; i++) { 27 if(i != root && d[i] == INF) { //除了root之外 有别的点无最小入边 28 return -1; 29 } 30 } 31 int cont = 0; 32 memset(id , -1 , sizeof(id)); 33 memset(vis , -1 , sizeof(vis)); 34 d[root] = 0; 35 for(int i = 0 ; i < V ; i++) { //找环 36 res += d[i]; 37 int v = i; 38 //vis[v] == i 表明找到一个环 id[v] != -1 表明这个点在循环中已经被下面的操作缩点(在环中) v == root 说明寻找到了根节点 39 while(vis[v] != i && id[v] == -1 && v != root) { //每个点寻找前序节点 要么找到根部 要么找到一个环 40 vis[v] = i; 41 v = pre[v]; 42 } 43 if(v != root && id[v] == -1) { //成环 缩点 44 for(int u = pre[v] ; u != v ; u = pre[u]) { 45 id[u] = cont; 46 } 47 id[v] = cont++; 48 } 49 } 50 if(cont == 0) { //无环 break 51 break; 52 } 53 for(int i = 0 ; i < V ; i++) { 54 if(id[i] == -1) { //没有成环的点 55 id[i] = cont++; 56 } 57 } 58 for(int i = 0 ; i < E ; i++) { //重新建图 重新标记 59 int u = edge[i].u , v = edge[i].v; 60 edge[i].u = id[u] , edge[i].v = id[v]; 61 if(id[v] != id[u]) { 62 edge[i].w -= d[v]; //理解上面的文字描述 > . < !(特别是二) 63 } 64 } 65 V = cont; 66 root = id[root]; //新的根 67 } 68 } 69 70 int main() 71 { 72 73 }
写的(盗用的)有些匆忙...
转载于:https://www.cnblogs.com/Recoder/p/5008678.html
最小树形图(朱刘算法)相关推荐
- poj3164(最小树形图朱刘算法模板)
题目链接:http://poj.org/problem?id=3164 题意:第一行为n, m,接下来n行为n个点的二维坐标, 再接下来m行每行输入两个数u, v,表点u到点v是单向可达的,求这个有向 ...
- 最小树形图——朱刘算法
洛咕博客地址:−>ClickHere<−->Click Here<-−>ClickHere<−,求捧场 最近想找最小生成树的题做,奈何难度有限,点进的蓝题紫题都和& ...
- 生成树最小树形图 -- 朱刘算法详解
本文借鉴的博文: zephyr_pro dalao的blog 朱刘算法引入: (把一道最小树形图当作最小生成树来做了,wa了后以为是bug像个sb一样d了半天) 最小树形图和最小生成树都是要求总权值最 ...
- bzoj 4349: 最小树形图 朱-刘算法
最裸的最小树形图(←现在才学的弱渣). 显然只需要打一下一个堡垒,然后剩下的可以最后用最小的代价再打. 然后只要把图建出来跑一下朱-刘算法即可. 简单讲一下朱-刘算法吧(思想还是很简单的),下面只考虑 ...
- 最小树形图-朱刘算法详解 +例题解析
文章目录 最小树形图 定义 和最小生成树的区别 朱刘算法 思想 步骤 流程展示 算法实现 例题 POJ3164_Command_Network HDU2121_Ice_cream's_world_II ...
- NOIP模拟题 通讯 强连通分量缩点 最小树形图--朱刘算法
通讯 (message.cpp\c\pas) [问题描述] "这一切都是命运石之门的选择." 试图研制时间机器的机关SERN截获了中二科学家伦太郎发往过去的一条短信,并由此得知了伦 ...
- [UVA - 11865]Stream My Contest(最小树形图+朱刘算法)
本题过于简单,朱刘算法模板题,考虑二分一下带宽即可 title code title code #include <cstdio> #include <cstring> #in ...
- 最小树形图+朱刘算法
大题上完整的朱.刘算法是由四个大步骤组成的: 1.求最短弧集合E 2.判断集合E中有没有有向环,如果有转步骤3,否则转4 3.收缩点,把有向环收缩成一个点,并且对图重新构建,包括边权值的改变和点的处理 ...
- 最小树形图——朱刘算法学习小记
参考资料: https://www.cnblogs.com/hdu-zsk/p/8167687.html https://www.luogu.com.cn/blog/xiaojiji/solution ...
最新文章
- v-model无法对返回的数据进行填写_学会数据分析思维,学会透过事物看本质
- ceres实现的pnp解算后的位姿优化代码详解
- 禁用任何未使用的端口com_分享连接思科路由器控制台端口的正确设置
- Circle Line
- DS博客作业07--查找
- 报告预测:到2027年,全球数据中心基础设施市场规模将达1423.1亿美元
- LeetCode 110 Balanced Binary Tree 平衡二叉树
- 八、马科维茨投资组合
- 计算机一级b需要学哪些,希望通过江苏省计算机一级B考试的同学千万要看哦!江苏省计算机一级B理论复习资料(绝密资料)...
- AHK-UMSS框架 (AHK通用修饰键解决方案,任何键都是修饰键)
- php sql查看本月记录,SQL Server 获取本周,本月,本年等时间内记录
- Flutter实战一Flutter聊天应用(三)
- 什么是复制和交换习语?
- php有的图片显示不出来,图片显示不出来,但是数据库里有显示
- csdn中下载资源入口查找
- 知识竞赛软件/答题系统/答题小程序
- 2020年8月8日美团笔试题
- 红帽子linux转中文后乱码,安装redhat时中文显示乱码(小方框)解决方法
- Hadoop YARN架构设计要点
- 基于DES和RSA算法自动分配密钥的加密聊天程序
热门文章
- 使用GruntJS构建Web程序 (1)
- [转载]Android: 如何实现ScrollView中含有ListView?
- C#+Mapxtreme 实现一些GIS系统基本的功能
- Oracle 索引扫描的五种类型
- 架构实战项目心得(三):JAVA和MAVEN的环境配置
- Handlebars.js 模板引擎
- iOS开发日记1-tableview编辑
- 信息化的“五观”与“N为”
- 转帖DataTable批量插入数据库
- 一起学 c++(二)