朱刘算法
时间:2019-12-13
本文章向大家介绍朱刘算法,主要包括朱刘算法使用实例、应用技巧、基本知识点总结和需要注意事项,具有一定的参考价值,需要的朋友可以参考一下。
有这样一类问题:一个n个点m条边的有向图中,找到一颗总边权最小的生成树,使得根节点能到达任意一个点(这样的一颗树就叫做这个图的最小树形图);
我们怎么暴力怎么来:
1.首先,我们对于图中的每个点y求出所有出边指向y中边权最小的点x,对于(x,y)建立父子关系;2.
2.然后我们按照这个关系得到一个图,由于自环不可能出现在生成树中,所有清除所有的自环;
3.如果这个图不存在强联通分量(环),那么这棵树就是一个最小树形图;
4.如果不是呢?我们将图中每个强联通分量缩成一个点,表示这个强联通分量中所有边都会选择;
5.然显然,这个强联通分量中不可能选取所有的边,那么采取可反悔贪心的思想:把所有出边指向这个(强联通分量中的点x)的(边权w)减去(与点x存在父子关系的点y)之间的(边权k),这意味着如果以后要选择边w,那么就要断去边k,额外的代价就是w-k;
6.然后缩完点后得到一个新的图,重复步骤1,直到出现步骤3,此时的总代价便是最小树形图的边权最小值;
这就是朱刘算法(其实本质就带反悔贪心的暴力啦~)
#include <cstdio> using namespace std; typedef long long ll; const int maxn=1e2+50; const int maxm=1e4+50; const int inf=0x3f3f3f3f; int n,m,r; ll ans; inline int read() { int a=0;char c=getchar(); while(c<'0'||c>'9') c=getchar(); while(c>='0'&&c<='9') a=(a<<1)+(a<<3)+c-'0',c=getchar(); return a; } struct edge {int u,v,w;}e[maxm]; int cnt,fa[maxn],id[maxn],top[maxn],min[maxn]; //cnt当前图环的数量 //id[u]代表u节点在第id[u]个环中 //top[u]代表u所在链的代表元素 类似并查集 //min[u]为当前连到u点的最短边的边权 fa[v]当前连到v点的最短边的u inline int getans() { while(1) { for(register int i=1;i<=n;++i) id[i]=top[i]=0,min[i]=inf; for(register int i=1;i<=m;++i) if(e[i].u!=e[i].v&&e[i].w<min[e[i].v]) //不是自环 并且边权比选定的还小 fa[e[i].v]=e[i].u,min[e[i].v]=e[i].w; int u=min[r]=0; for(register int i=1;i<=n;++i) { if(min[i]==inf) return 0; //存在一个不可以连接的点 ans+=min[i]; for(u=i;u!=r&&top[u]!=i&&!id[u];u=fa[u]) top[u]=i; //找到包含不在环中的点最多的链 打上标记 if(u!=r&&!id[u]) { //这时候还满足条件说明vis[u]==i 即成环 id[u]=++cnt; for(int v=fa[u];v!=u;v=fa[v]) id[v]=cnt; } }if(!cnt) return 1; //没环就是找到答案了 for(register int i=1;i<=n;++i) if(!id[i]) id[i]=++cnt; //i节点不存在当前树中 就给他自己成一个环 for(register int i=1;i<=m;++i) { int last=min[e[i].v]; //last等于当前连进v点的边的最小权值 if((e[i].u=id[e[i].u])!=(e[i].v=id[e[i].v])) e[i].w-=last; //当前边的两个端点不在同一个环内 }n=cnt;r=id[r];cnt=0; //缩完点后 当前点数就为环数 根节点就是根节点所在的环 } } int main() { n=read();m=read();r=read(); for(register int i=0;i<m;e[++i]=(edge){read(),read(),read()}); if(getans()) printf("%lld",ans); else printf("-1"); return 0; }
原文地址:https://www.cnblogs.com/kamimxr/p/12035724.html
- 1578: [Usaco2009 Feb]Stock Market 股票市场
- webp图片实践之路
- 3522: [Poi2014]Hotel
- 3299: [USACO2011 Open]Corn Maze玉米迷宫
- 2272: [Usaco2011 Feb]Cowlphabet 奶牛文字
- 1632: [Usaco2007 Feb]Lilypad Pond
- 1630/2023: [Usaco2005 Nov]Ant Counting 数蚂蚁
- Java设计模式(七)Decorate装饰器模式
- 1623: [Usaco2008 Open]Cow Cars 奶牛飞车
- 1622: [Usaco2008 Open]Word Power 名字的能量
- 3297: [USACO2011 Open]forgot
- 1740: [Usaco2005 mar]Yogurt factory 奶酪工厂
- 1741: [Usaco2005 nov]Asteroids 穿越小行星群
- 3298: [USACO 2011Open]cow checkers
- 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 数组属性和方法