基环树学习笔记
前言
emmmm,没有什么想要说的
算法概述
基环树啊,经过我粗浅的学习,认为它是将环和树边分开处理,具体来说就是每次强制断掉环中的任意一条边来处理。(我觉得说不上算法,可能只是一种数据结构或者巧妙的思想?
反正就是很妙啊。。。
定义
基环树,也是环套树,一种有 \(n\) 个点 \(n\) 条边 的图, 即在一棵 \(n\) 个点的树的基础上在任意两点(没有直接连边)之间在连上一条边的图。
可能有点抽象其实还好,看看下面我盗的图吧(
- 无向树
- 外向树
- 内向树
所以基环树的性质不多,根据上面我们就可以得到最显然的一条:
- 点数与边数相同。
就这?!
对没错,就这(
前置知识
拓扑排序
用来处理无向图,找到环上的每一个点啦。
基本流程:
- 找到入度为 \(1\) 的点入队
- 每次取出队首,将与队首相连的所有点的入度分别减 \(1\)
- 重复以上操作,知道队列为空
\(Code:\)
void t_sort() {
int l = 0, r = 0, now, ver;
for(int i = 1; i <= n; i ++) {
if(in[i] == 1) sta[++r] = i;
}
while(l < r) {
now = sta[++l];
for(int i = head[now]; i; i = e[i].nex) {
ver = e[i].to;
in[ver] --;
if(in[ver] == 1) sta[++r] = i;
}
}
}
这样处理之后,按理来说所有点的入度都应该 \(\le\) \(1\), 但是因为有环,所以存在入度 \(\ge\) \(1\)。
所以在拓扑之后,再搜一遍,入度 \(\ge\) \(1\) 的都是环上的点, 就找到整个环的位置啦~
DFS
这个没什么要讲的。
\(Code:\)
void dfs(int x) {
int ver;
sta[++cnt] = x, vis[x] = 1;
for(int i = head[x]; i; i = e[i].nex) {
ver = e[i].to;
if(rel[x][ver] || vis[ver]) continue;
dfs(ver);
}
}
注意: \(dfs\) 的代码并没有模板化,上面给出的代码仅仅只是为了介绍 \(dfs\),并不是用于所有的基环树。具体实现要看题目要求而定。
应用
断环法
应该算是最常见的方法吧?
顾名思义,断环法其实就是每次通过断掉环上任意一条边,使其变成一棵 \(n - 1\) 条边的树,在树上跑一遍答案。最后取满足条件的最大值或者最小值。
这样感觉就是暴力嘛,所以只适用于数据范围很小而且环的存在(也就是断掉环上的一条边之后)不会影响答案的情况。
经典例题 :[NOIP2018 提高组] 旅行
题目大意:在一个连通的 \(n\) 个点 \(n - 1\) 或者 \(n\) 条边的无向图上,从任意一点出发,沿边遍历每一个点,求字典序最小的遍历顺序。
二次dp法
断环复制法
总结
总的来说,基环树还是很巧妙滴~
一般基环树的题都有很明显的特征,要么就是题面直接告诉你这是一棵基环树,要么就是描述为“ \(n\) 点 \(n\) 条边 无重边无自环保证联通”……
这个时候
参考博客
原文地址:https://www.cnblogs.com/Spring-Araki/p/14668934.html
- RabbitMQ入门-高效的Work模式
- 谈谈分布式事务之四: 两种事务处理协议OleTx与WS-AT
- RabbitMQ入门-从HelloWorld开始
- RabbitMQ入门-从HelloWorld开始
- RabbitMQ入门-初识RabbitMQ
- 谈谈分布式事务之三: System.Transactions事务详解[下篇]
- 当InternalsVisibleToAttribute特性遭遇"强签名"
- MyBatis-从查询昨天的数据说起
- WCF并发(Concurrency)的本质:同一个服务实例上下文(InstanceContext)同时处理多个服务调用请求
- Spring集成RabbitMQ-必须知道的几个概念
- Spring读书笔记——bean创建(上)
- 15:21爆出的小程序功能升级,你还要对小程序观望吗?
- 如何解决分布式系统中的跨时区问题[原理篇]
- 什么是区块链:块的结构
- 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 数组属性和方法
- 解决Ajax发送DELETE请求时后台无法接收到参数的问题(Restful风格)
- 解决layui的table数据重载reload where参数会保留上次条件的问题
- 终于弄懂了Layui表格重载数据
- 剑指Offer LeetCode 面试题21. 调整数组顺序使奇数位于偶数前面
- 剑指Offer LeetCode 面试题17. 打印从1到最大的n位数
- 剑指Offer LeetCode 面试题15. 二进制中1的个数
- 剑指Offer LeetCode 面试题11. 旋转数组的最小数字
- 剑指Offer 面试题09. 用两个栈实现队列
- 剑指Offer 面试题06. 从尾到头打印链表
- 剑指Offre 面试题05. 替换空格
- Datatables获取选中行的某一列的数据
- 终于懂了建造者模式
- (力扣)面试题04. 二维数组中的查找
- 一条命令查询电脑多久没关机
- Android Studio无法运行程序调试程序出现Unable to connect to ADB.Check the Event Log for possible issues.Verify th