Description
欧拉路:图中经过所有边恰好一次的路径
欧拉回路:起点和终点相同的欧拉路
判定
分为有向图和无向图两种情况:
(1.) 无向图
((1)) 所有点的度数都是偶数,此时起点任选两个即可
((2)) 恰好有两个点的度数是奇数,此时两个奇度数点为起点或终点
(2.) 有向图
((1)) 所有点的入度都等于出度,此时存在欧拉回路,所有点都可以做起点
((2)) 有两个点入度不等于出度,同时满足两个点有一个入度大于出度,有一个入度小于出度,此时出度大的是起点,入度大的是终点
Hierholzer算法
(挺简单的)
暴力算法就是对于当前到的点,枚举所有的出边
然后如果没访问过就搜过去
复杂度 (O(nm))
然后发现缺陷在于每次都从头开始,这并不优秀,加上一个类似 (dinic) 当前弧优化的东西就行了
inline void dfs(int x)
{
for(int i=head[x];i;i=e[i].nxt)
{
if(vis[i]) continue;
int t=e[i].to; vis[i]=vis[i^1]=1;
head[x]=i; dfs(t); i=head[x];
}
return st[++top]=x,void();
}
复杂度 (O(n+m))
看 (Rorschach-XR) 的博客里面写这种东西递归太慢了?
int x,r[N*10],i,cnt,top,st[N*10];
inline void find()
{
st[++top]=1;
while(top)
{
int x=st[top],i=head[x];
while(vis[i]) i=e[i].nxt;
if(i)
{
int t=e[i].to;
vis[i]=vis[i^1]=1;
head[x]=i;
}
else top--,r[++cnt]=x;
}
return ;
}
答案就是栈内元素的倒序
其实找欧拉路可能见的少,但是有欧拉路的相关性质倒是很常用
例题
Hdu3018
给定一个 (n) 点 (m) 边的有向图
要遍历每个点恰好一次,每次可以沿着边走
求最少指定多少个起点?
每个无向图上的欧拉路满足的是起点和终点都是入度为 (2) 所以
对于每个联通块考虑,直接找有多少个点的度数是奇数, (lfloorfrac {num+1} 2 floor) 即可
星际旅行
每条边拆成两个
拆完之后入度必然是偶数
然后删掉一些两条边使得图上有一条欧拉路即可
这就直接从度数角度考虑就行了
(1.) 删掉两个自环
(2.) 删掉一个自环和随便这个点连一个边
(3.) 删掉两条这个点出发的边
(挺好的一个性质题目)