标签:alt 网络 它的 欧拉回路 假设 use 起点 保存 访问
都初三了还不会这个就有点丢人了吧
一个相当 water 的东西哦/doge
对于图 \(G=(V,E)\),给出以下定义:
欧拉回路:图 \(G\) 中经过每条边恰好一次的回路。
欧拉路径:图 \(G\) 中经过每条边恰好一次的路径。
这里不加证明地给出以下定理:
类似地,我们也得到的有向图的欧拉路径/回路的判定方式:
无向图/有向图的欧拉回路/欧拉路的求法是类似的,知道其中一个的求法也就能顺带着推出另外三个的求法,这里以无向图的欧拉回路的求法为例。
首先任选一个点为起点(由于是欧拉回路,任选一个点为起点都没问题,如果是欧拉路径的情况就按照上面判定的思路找到起点),然后重复以下的操作:从起点开始 DFS,每次访问一个节点 \(u\),就遍历它的邻居找到一个未访问过的边 \((u,v)\) 并从 \(v\) 点继续 DFS 下去并标记 \((u,v)\) 为“已经访问过”,不难证明我们从 \(v\) 开始 DFS 下去的过程中一定会回溯到 \(u\),也就是从 DFS \(v\) 到回溯到 \(u\) 的部分一定还是一个欧拉回路(否则假设 \(v\) 到达某个点 \(w\) 之后无路可走了,那么在这之前由于每次访问 \(w\) 都是从某个点到达 \(w\),再从 \(w\) 走向某个点,会消灭掉 \(2\) 条与 \(w\) 相连的边,而这次访问到 \(w\) 时只消灭了一条与 \(w\) 相连的边,之后 \(w\) 的度数就变为 \(0\) 了,也就是说 \(w\) 的度数为奇数,与欧拉回路的条件“所有点的度数都是偶数”矛盾)。回溯的时候就将边 \((u,v)\) 的信息压入 DFS 序列。正确性显然。
不过这个做法的复杂度是错误的,比方说下图:
不难发现我们回溯到 \(1\) 的次数为 \(10^5\),而我们每次回溯到 \(1\) 都要从头开始寻找第一个未访问过的边,也就是说当我们访问最后几个环的时候这个访问次数最高可达 \(10^5\),时间复杂度也就退化到了 \(10^5\times 10^5=10^{10}\),直接爆炸。这里可以借鉴网络流中“当前弧优化”的思想,记录一个 \(now_x\) 表示当前访问到了哪条边,每次寻找第一个未访问过的边时就从 \(now_x\) 开始遍历即可,这样复杂度就降到了 \(\mathcal O(|E|)\)。相信学过网络流的同学这一步都不难理解。
int hd[MAXN+5],to[MAXN*2+5],nxt[MAXN*2+5],ec=1;//边从 1 开始编号
bool used[MAXN+5];vector<int> ret;
void adde(int u,int v){to[++ec]=v;nxt[ec]=hd[u];hd[u]=ec;}
void cir(int x){
for(int &e=hd[x];e;e=nxt[e]) if(!used[e>>1]){
used[e>>1]=1;int tmp=e;//注意保存临时变量
cir(to[e]);ret.pb(e);
}
}
标签:alt 网络 它的 欧拉回路 假设 use 起点 保存 访问
原文地址:https://www.cnblogs.com/ET2006/p/euler-circuit.html