欧拉回路整理

chunlvxiong的博客


一、定义:

  若一个图G存在一条路,经过G中每条边有且仅有一次,称这条路为欧拉路。

  如果这是一条回路称为欧拉回路,同时这个图G称为欧拉图。

二、判定方法

无向图:

  欧拉路:图连通,有2个奇点,欧拉路从一个奇点出发,到另一个奇点结束。

  欧拉回路:图连通,有0个奇点,欧拉回路可从任意点开始。

有向图:

  欧拉图:图连通,有一个点X出度=入度+1,另一个点Y入度=出度+1,其余点出度=入度,欧拉路从X点开始,到Y点结束。

  欧拉回路:图连通,所有点出度=入度,欧拉回路可从任意点开始。

三、输出路径

  这里考虑如何输出无向图的欧拉路或欧拉回路(假设存在)。

fleury算法:

  首先要从一个正确的点开始DFS(实际上这个点是作为结束点的)。然后对于每个点DFS其所有连边所到的点,且每次DFS之前删除掉那条边。当所有DFS完成之后输出这个点即可。

  个人理解:

  称一个奇点S到另一个奇点T的路称为主路径,则其余所有路径都是环。

  从S开始DFS,如果碰到的边通向的是一条环,自然最后会回到S点,由于S点的连边并没有全部删光,所以这个环不会打出。如果碰到的边通向的是主路径,那么它会直接打出从T到S的路径(当然中间附带的环也会打好),即它会优先保证打出主路径,然后再打出环,因而不会导致错误。

  实现的时候使用链表而不是邻接矩阵以提高效率。

贴代码:

#include <bits/stdc++.h>
const int maxn=105;
const int maxm=1005;
int n,m,tot,head[maxn],last[maxn];
struct E{
    int to,next;
}edge[maxm*2];
int D[maxn];
bool vis[maxm];
void init(){
    memset(head,0,sizeof(head)),tot=0;
}
void makedge(int u,int v){
    edge[++tot].to=v;
    edge[tot].next=head[u];
    head[u]=tot;
}
void dfs(int u){
    for (int i=last[u];i;i=edge[i].next)
    if (vis[(i-1)>>1])
        last[u]=edge[last[u]].next;
    else{
        vis[(last[u]-1)>>1]=1;
        dfs(edge[last[u]].to);
        last[u]=edge[last[u]].next;
    }
    printf("%d\n",u);
}
int main(){
    scanf("%d%d",&n,&m),init();
    memset(D,0,sizeof(D));
    for (int i=1,x,y;i<=m;i++){
        scanf("%d%d",&x,&y);
        makedge(x,y),makedge(y,x);
        D[x]++,D[y]++;
    }
    int ODD=0,s=1;
    for (int i=1;i<=n;i++){
        last[i]=head[i];
        if (D[i]&1) ODD++,s=i;
    }
    if (ODD==0 || ODD==2){
        memset(vis,0,sizeof(vis));
        dfs(s);
    }
    else puts("No Eular path!");
    return 0;
}

  另类实现(网上广为流传的版本):

 贴代码:

#include <bits/stdc++.h>
const int maxn=105;
const int maxm=1005;
int n,m,tot,head[maxn],last[maxn];
struct E{
    int to,next;
}edge[maxm*2];
int top,stack[maxn],D[maxn];
bool vis[maxm];
void init(){
    memset(head,0,sizeof(head)),tot=0;
}
void makedge(int u,int v){
    edge[++tot].to=v;
    edge[tot].next=head[u];
    head[u]=tot;
}
void dfs(int u){
    stack[++top]=u;
    for (int i=last[u];i;i=edge[i].next)
    if (vis[(i-1)>>1])
        last[u]=edge[last[u]].next;
    else break;
    if (last[u]){
        vis[(last[u]-1)>>1]=1;
        dfs(edge[last[u]].to);
    }
}
void fleury(int x){
    stack[top=1]=x;
    while (top){
        int u=stack[top];
        for (int i=last[u];i;i=edge[i].next)
        if (vis[(i-1)>>1])
            last[u]=edge[last[u]].next;
        else break;
        if (!last[u]) printf("%d ",stack[top--]);
        else dfs(stack[top--]);
    }
}
int main(){
    scanf("%d%d",&n,&m),init();
    memset(D,0,sizeof(D));
    for (int i=1,x,y;i<=m;i++){
        scanf("%d%d",&x,&y);
        makedge(x,y),makedge(y,x);
        D[x]++,D[y]++;
    }
    int ODD=0,s=1;
    for (int i=1;i<=n;i++){
        last[i]=head[i];
        if (D[i]&1) ODD++,s=i;
    }
    if (ODD==0 || ODD==2){
        memset(vis,0,sizeof(vis));
        fleury(s);
    }
    else puts("No Eular path!");
    return 0;
}
posted @ 2017-08-22 19:38  chunlvxiong  阅读(310)  评论(1编辑  收藏  举报