「学习笔记」欧拉路 Description 判定 Hierholzer算法 例题

欧拉路:图中经过所有边恰好一次的路径

欧拉回路:起点和终点相同的欧拉路

判定

分为有向图和无向图两种情况:

(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.) 删掉两条这个点出发的边

(挺好的一个性质题目)