一、欧拉图:
  无向图连通性的小问题——欧拉路问题,俗称一笔画问题。

  给定一张无向图,若存在一条从节点S到节点T的路径,恰好不重不漏的经过每条边一次(可以重复经过图中的顶点),则称该路径为S到T的欧拉路。

  特别的,若存在一条从节点S出发的路径,敲好不重不漏的经过每条边一次(可以重复经过图中的节点),最终回到起点S,则称该路径为欧拉回路。存在欧拉回路的无向图被称为欧拉图。

  欧拉图的判定:
  一张无向图为欧拉图,当且仅当无向图连通,并且每个点的度数都是偶数。

  欧拉路的存在性判定:
  一张无向图中存在欧拉回路,当且仅当无向图连通,并且图中恰好有两个节点的度数为奇数,其他节点的度数都是偶数。这两个度数为奇数的节点就是欧拉路的起点S和终点T。

  在判定无向图存在欧拉回路之后,我们可以借助深度优先遍历和栈,求出欧拉回路的一种具体方案。//回溯时入队。

  欧拉图每个节点度数为偶数的说明:
  只要到达一个节点,就必定有一条尚未走过的边可以离开该点。

  假设我们采用邻接表存储无向图,我们可以在访问一条边(x,y)后,即使修改表头head(x),令它指向下一条边。这样我们每次只需取出head(x),就自然跳过了所有以访问过的边。
  另外,因为欧拉回路DFS的递归层数时O(m)级别,容易造成系统栈溢出。我们可以用另一个栈,模拟机器的递归过程,把代码转化为非递归实现。
  时间复杂度为O(n+m)。

#include<iostream>
#include<cstdio>
#include<algorithm>
#include<cstring>
#include<string>
#include<cmath>
#include<queue>
#include<vector>
#define ll long long
using namespace std;
const int maxn=100010;
int head[maxn],ver[maxn],nt[maxn],tot;
int st[maxn],ans[maxn];
bool vis[maxn];
int n,m,top,t;

void add(int x,int y)
{
    ver[++tot]=y,nt[tot]=head[x],head[x]=tot;
}

void euler(void)
{
    st[++top]=1;
    while(top>0)
    {
        int x=st[top],i=head[x];
        while(i&&vis[i]) i=nt[i];

        if(i)
        {
            st[++top]=ver[i];
            vis[i]=vis[i^1]=true;
            head[x]=nt[i];
        }
        else
        {
            top--;
            ans[++t]=x;
        }
    }
}

int main(void)
{
    cin>>n>>m;
    tot=1;

    int x,y;
    for(int i=1;i<=m;i++)
    {
        scanf("%d%d",&x,&y);
        add(x,y);
        add(y,x);
    }
    euler();
    for(int i=t;i;i--) printf("%d\n",ans[i]);

    return 0;
}

  例题:POJ2230 Watchcow:
  题意:给定N各点,M条边的无向图(1≤N≤104,1≤M≤5*104),求一条路径,从节点1出发,最后回到节点1,并且满足每条边恰好被沿着正反两个方向分别经过一次。若有多种方案,输出任意一种即可。
  我们只需要在求欧拉回路的参考程序中,去掉对每条边的vis标记,即可得到本题的解答。这是因为,按照一般的存储方式,每条无向边在邻接链表中会以正反两个方向分别保存一次。若没有vis标记,则根据表头数组head的更新方法,每条无向边会被正,反两个方向各经过一次,恰好符合题目要求。

#include<iostream>
#include<cstdio>
#include<algorithm>
#include<cstring>
#include<string>
#include<cmath>
#include<queue>
#include<vector>
#define ll long long
using namespace std;
const int maxn=100010;
int head[maxn],ver[maxn],nt[maxn],tot;
int st[maxn],ans[maxn];
int n,m,top,t;

void add(int x,int y)
{
    ver[++tot]=y,nt[tot]=head[x],head[x]=tot;
}

void euler(void)
{
    st[++top]=1;
    while(top>0)
    {
        int x=st[top],i=head[x];

        if(i)
        {
            st[++top]=ver[i];
            head[x]=nt[i];
           // printf("%d***\n",ver[i]);
        }
        else
        {
            top--;
           // printf("%d**\n",x);
            ans[++t]=x;
        }
    }
}

int main(void)
{
    while(scanf("%d%d",&n,&m)!=EOF)
    {
        tot=1;top=0;t=0;
        for(int i=1;i<=n;i++)
            head[i]=0;
        int x,y;
        for(int i=1;i<=m;i++)
        {
            scanf("%d%d",&x,&y);
            add(x,y);
            add(y,x);
        }
        euler();
        for(int i=t;i;i--) printf("%d\n",ans[i]);

    }

    return 0;
}