朱刘算法
时间:2019-08-21
本文章向大家介绍朱刘算法,主要包括朱刘算法使用实例、应用技巧、基本知识点总结和需要注意事项,具有一定的参考价值,需要的朋友可以参考一下。
一个有向图,存在从某个点为根的,可以到达所有点的一个最小生成树,则它就是最小树形图。
朱刘算法用来求最小树形图,复杂度O(nm)。
大概思想就是缩点+贪心加边。
如果图中存在环,就把环缩成一个点,一直到没有环为止。
考虑正确性:
最小树形图和最小生成树的区别就在与有方向,对于一个环,我们可以选择一条入边+所有环边-1(-1是因为有一条入边可以去掉一条环边)
而对于每一个点,我们用一个minn数组存下了与它直接相连的点到它的最小边,ans等于所有minn的累加,那么一定是最优解。
用while一直执行缩点过程。
注意:vis用来避免一直走环。
具体流程和解释代码中给出(借鉴洛谷题解)
#include<bits/stdc++.h> #define N 103 #define M 10002 #define INF 210000001 #define LL long long using namespace std; int read() { int x=0,f=1;char s=getchar(); while(s<'0'||s>'9'){if(s=='-')f=-1;s=getchar();} while(s>='0'&&s<='9'){x=x*10+s-'0';s=getchar();} return x*f; } struct EDGE{ int a,b,v; }w[M]; int minn[N],id[N],vis[N],fa[N]; int cnt=0; //cnt当前图环的数量 //id[u]代表u节点在第id[u]个环中 //vis[u]打标记避免一直走环 //minn[u]为当前连到u点的最短边的边权 fa[v]当前连到v点的最短边的u LL ans=0; int zhuliu(int n,int m,int r) { while(1) { for(int i=1;i<=n;++i) minn[i]=INF,id[i]=vis[i]=0; for(int i=1;i<=m;++i) { if(w[i].a!=w[i].b&&w[i].v<minn[w[i].b])//不是自环 并且边权比选定的还小 fa[w[i].b]=w[i].a,minn[w[i].b]=w[i].v; } int u; minn[r]=0; for(int i=1;i<=n;++i) { if(minn[i]==INF)return 0;//存在一个不可以连接的点,什么不能找到最小树形图 ans+=minn[i];//这里就会更新到ans中 for(u=i;u!=r&&!id[u]&&vis[u]!=i;u=fa[u])vis[u]=i;//打上标记,这里走过的是一条链,vis打上i而不是1,因为可能多条边指向一个点 if(u!=r&&!id[u])//没有走到根,找到一个新环 { id[u]=++cnt; for(int v=fa[u];v!=u;v=fa[v])id[v]=cnt; } } if(!cnt)return 1;//没有环了,说明现在就是最小树形图,边权和在上面就已经加入ans了 for(int i=1;i<=n;++i) if(!id[i])id[i]=++cnt;//i节点不存在当前树中 就给他自己成一个环 for(int i=1;i<=m;++i) { int last=minn[w[i].b];//last等于当前连进v点的边的最小权值 if((w[i].a=id[w[i].a])!=(w[i].b=id[w[i].b]))w[i].v-=last; //缩环的时候记得加入答案,环上的出边直接接上,入边要注意,选一条入边相当于删掉一条环边 //当前边的两个端点不在同一个环内 } n=cnt;cnt=0;r=id[r];//缩完点后 当前点数就为环数 根节点就是根节点所在的环 } } int main() { int n=read(),m=read(),r=read(); for(int i=1;i<=m;++i) w[i].a=read(),w[i].b=read(),w[i].v=read(); if(zhuliu(n,m,r))printf("%lld\n",ans); else printf("-1\n"); }
再放一个没有注释的
#include<bits/stdc++.h> #define N 103 #define M 10002 #define INF 210000001 #define LL long long using namespace std; int read() { int x=0,f=1;char s=getchar(); while(s<'0'||s>'9'){if(s=='-')f=-1;s=getchar();} while(s>='0'&&s<='9'){x=x*10+s-'0';s=getchar();} return x*f; } struct EDGE{ int a,b,v; }w[M]; int minn[N],id[N],vis[N],fa[N]; int cnt=0; LL ans=0; int zhuliu(int n,int m,int r) { while(1) { for(int i=1;i<=n;++i) minn[i]=INF,id[i]=vis[i]=0; for(int i=1;i<=m;++i) { if(w[i].a!=w[i].b&&w[i].v<minn[w[i].b]) fa[w[i].b]=w[i].a,minn[w[i].b]=w[i].v; } int u; minn[r]=0; for(int i=1;i<=n;++i) { if(minn[i]==INF)return 0; ans+=minn[i]; for(u=i;u!=r&&!id[u]&&vis[u]!=i;u=fa[u])vis[u]=i; if(u!=r&&!id[u]) { id[u]=++cnt; for(int v=fa[u];v!=u;v=fa[v])id[v]=cnt; } } if(!cnt)return 1; for(int i=1;i<=n;++i) if(!id[i])id[i]=++cnt; for(int i=1;i<=m;++i) { int last=minn[w[i].b]; if((w[i].a=id[w[i].a])!=(w[i].b=id[w[i].b]))w[i].v-=last; } n=cnt;cnt=0;r=id[r]; } } int main() { int n=read(),m=read(),r=read(); for(int i=1;i<=m;++i) w[i].a=read(),w[i].b=read(),w[i].v=read(); if(zhuliu(n,m,r))printf("%lld\n",ans); else printf("-1\n"); }
原文地址:https://www.cnblogs.com/yyys-/p/11348556.html
- JavaScript 教程
- JavaScript 编辑工具
- JavaScript 与HTML
- JavaScript 与Java
- JavaScript 数据结构
- JavaScript 基本数据类型
- JavaScript 特殊数据类型
- JavaScript 运算符
- JavaScript typeof 运算符
- JavaScript 表达式
- JavaScript 类型转换
- JavaScript 基本语法
- JavaScript 注释
- Javascript 基本处理流程
- Javascript 选择结构
- Javascript if 语句
- Javascript if 语句的嵌套
- Javascript switch 语句
- Javascript 循环结构
- Javascript 循环结构实例
- Javascript 跳转语句
- Javascript 控制语句总结
- Javascript 函数介绍
- Javascript 函数的定义
- Javascript 函数调用
- Javascript 几种特殊的函数
- JavaScript 内置函数简介
- Javascript eval() 函数
- Javascript isFinite() 函数
- Javascript isNaN() 函数
- parseInt() 与 parseFloat()
- escape() 与 unescape()
- Javascript 字符串介绍
- Javascript length属性
- javascript 字符串函数
- Javascript 日期对象简介
- Javascript 日期对象用途
- Date 对象属性和方法
- Javascript 数组是什么
- Javascript 创建数组
- Javascript 数组赋值与取值
- Javascript 数组属性和方法
- 实现一个简单的WebSocket聊天室
- 使用 trash 避免 rm -rf 悲剧
- 快速学习-Saturn Executor部署
- LeetCode70——爬楼梯
- 快速学习-Saturn创建Namespace
- 理解 Node.js 的 GC 机制
- LeetCode176——第二高的薪水
- 快速学习-Saturn QuickStart
- 快速学习-开发你的作业
- 理解Spring中的IoC和DI
- 快速学习-Saturn性能测试报告
- Java源码系列1——ArrayList
- 【Kubernetes】自定义资源CRDs不支持fieldselector
- Cypress系列(48)- and() 命令详解
- Java源码系列2——HashMap