欧拉路,欧拉回路
求一个图的欧拉路:\(Hierholzer\) 算法
set<int> G[N];
vector<int> euler_path;
void dfs(int u){
while(!G[u].empty()){
int v = *G[u].begin();
G[u].erase(v);
G[v].erase(u);
dfs(v);
}
euler_path.pb(u);
}
dfs(start); // 奇数度点数为0时,任意点均可;为2时,只能是两个端点
注意在有向图中,经上述算法求出的欧拉路是倒序的,需要 \(reverse\);而无向图不存在反转的问题。
如果图的规模足够小,可以直接用邻接矩阵存图;由于涉及到删边,需要用 \(set\) 存图,而不能用 \(vector\)。
理解:深搜过程中,优先将无出边的点放入答案路径中,而无出边的点必然对应欧拉路的末尾,因此可以理解为存储的路径是原图倒序的欧拉路。
这种写法用 set 存图,复杂度会徒增一个 \(\log\),但写法更简便;可以通过对边标编号和 \(vis\) 数组来优化复杂度。
de Bruijn序列 模板题
Q:给定 \(n,k\),构造一个只包含数字 \([0,k-1]\) 的序列,要求在长度最短的前提下字典序最小;考虑其所有连续子串,包含 \(k\) 进制下全部 \(n\) 位数字。\(n \leq 4,k \leq 10\)。
首先确定最短长度应该是多少:显然为 \(k^{n}+n-1\),因为长度为 \(n\) 的 \(k\) 进制序列一共有 \(k^{n}\) 种,每种互不相同,因此至少要有 \(k^{n}\) 个不同的位置作为每一种的开头;而对于在末尾的开头位置,为了保证其序列共 \(n\) 位,至少还需要往末尾添加 \(n-1\) 个数字。因此,理论上的最小长度为 \(k^{n}+n-1\),实际上也是如此。
而构建序列的过程,需要利用有向图的欧拉回路。
以 \(n=3,k=2\) 为例:
构建一个有向图:结点是所有 \(n-1\) 位 \(k\) 进制数的集合,总共 \(k^{n-1}\) 个结点,边权是 \(1\) 位 \(k\) 进制数的集合,总共 \(k\) 种出边;每个结点均有 \(k\) 条出边,两点间出边的定义类似于两数之间在 \(k\) 进制下循环左移一位后的结果,具体可见上图。
显然对于该有向图,每个结点的入度均等于出度(均为 \(k\)),且整个图强联通,因此必然可以对该图求出一条欧拉回路。
结论:对该有向图求出欧拉回路,起点 + 欧拉回路 拼接形成的序列长度恰为 \(k^{n}+n-1\),且一定满足要求 “考虑其所有连续子串,包含 \(k\) 进制下全部 \(n\) 位数字”。为满足其字典序最小,显然只需要让起点代表数字的字典序最小,即全 \(0\)。
具体实现见 code。
P10950
与上一道题的唯一区别在于构造的是循环序列。
只需要省略求出的欧拉回路的后 \(n-1\) 个数字即可,最小长度是 \(k^{n}\)。
证明:因为欧拉回路的起点代表数字是 \(n-1\) 个 \(0\),由于是回路,终点也是该点。从有向边的定义可以看出来,欧拉回路的最后 \(n-1\) 个数字一定都是 \(0\)(\(n-1\) 次末尾补齐)。而起点也是 \(n-1\) 个 \(0\),显然可以省略后面 \(n-1\) 个 \(0\),使得序列仍然覆盖所有可能。
P3520
欧拉回路可以看作是若干个简单环路的组合。
将欧拉回路拆分成若干简单环路 trick —— 只需要稍稍改写 \(Hierholzer\) 算法。
Q:给定 \(n\) 个点 \(m\) 条边的无向图(不一定连通),其中每条边只有 \(2\) 种可能的状态:\(0\) 或 \(1\)。\(0\) 代表不需要翻转,\(1\) 代表需要翻转。可以安排任意数量的垃圾车,每辆垃圾车必须经过一条简单环路(即简单环,只有首尾点相同,中途经过的若干点无重复),每次经过一条边时翻转该边的状态,要求所有边都达到其对应状态,给出任意一种合法方案。
首先给出结论:对于不需要翻转的边,可以直接删除;需要翻转的边只需要用一辆垃圾车经过该边。因为对于不需要翻转的边,只能有偶数辆垃圾车经过该边;而对于经过该边的所有不同的环,可以通过忽视该边将它们拼接成一个更大的环;需要翻转的边也是同理。本质上就是只要 \(2\) 个不同的环共享某一条边,那么就可以忽视该边,将两个环合并成一个环。
又一个结论:对于所有的连通块,若该连通块存在欧拉回路(即每个点的度数均为偶数),则有解,否则无解。因为经过上述将图处理后,剩下的每条边均需要翻转,且只能经过一次,显然是欧拉回路的特征。在求该连通块的欧拉回路(即 \(Hierholzer\) 算法)过程中,若重复经过了某个点,说明产生了环,处理出该环并分配一辆垃圾车即可。
具体实现见 code。
P3443
Q:给定 \(n\) 个点 \(m\) 条边的有向图,要求从 \(1\) 号点出发,最终回到 \(1\) 号点,每条边恰好经过一次(即起点为 \(1\) 号点的欧拉回路),并给定 \(t\) 个任意长度的序列,要求对于任意一个序列均出现在该回路的某个连续子段中,问是否存在这样的回路,并输出方案。
待补。。。





浙公网安备 33010602011771号