先放一些结论:
//欧拉路径:通过图中每条边恰好一次的路径。
//(起点与终点不同时的判据)
//有向图:起点出度比入度多 1,终点入度比出度多 1,其余点出入度相等。
//无向图:起点和终点是奇度数,其余点偶度数。
//欧拉回路:起点和终点相同的欧拉路径。
//有向图:所有点出入度相同。
//无向图:所有点偶度数。
这里主要讲一下欧拉路径,欧拉路径通俗来说就是一个图一笔画的轨迹,由上面的结论也知道,对于有向图来说,因为要一笔画,中间点肯定是有进有出故入度和出度相同,起点出发所以起点的入度少一,终点的出度少一。所以建图时顺便统计一下每个结点的入度和出度,当所有的结点入度和出度相同时,就说明可以随意从一个结点出发,最终能回到这个结点,任意一个结点都能够作为起点。
下面放一道洛谷的模板题,洛谷P7771【模板】欧拉路径
题目保证了图是连通的,要求输出字典序最小的欧拉路径。首先欧拉路径为了不漏环,所以我们需要在dfs时后序遍历,并倒叙输出(记住这个结论要这样做就行,具体证法去别的地方找找),所以我们需要用栈来记录后序遍历的点编号。并且因为要求字典序最小,我们存图后要对邻接表vector排序一下,让dfs时优先到达编号小的结点。然后在dfs的同时,删除已经访问过的边。
这里迎来了我当初一直卡的地方,也就是删边。我第一反应是用一个map存一下访问过的边,用结点代表出发点和到达点。然后一直过不去,后面控制变量一下我换了别人的删边方式就过了,发现因为这道题没有说保证不重边的情况,所以有可能出现反复横跳的情况,所以两个节点之间不一定只有一条边,故不能用map记录结点的方式来删边,下面放一下我的错误示范:
void dfs(int u){
for(auto v:G[u]){
if(vis[u][v]!=1) vis[u][v]=1,dfs(v);
}
sta[++top]=u;
}
那么应该如何正确删边呢?这里是用一个数组,记录每个结点应该要访问的下一个结点在邻接表里的下标,然后下次如果又路过这个点,就直接从这个数组对应的值下标访问邻接表,就可以起到删边的效果了,所有代码如下:
#include<bits/stdc++.h>
#define ll long long
#define pii pair<int,int>
const int maxn=100010,maxm=100010;//!注意,边和点的max值可能不一样
using namespace std;
vector<int>G[maxn];
int in[maxn],out[maxn];//记录结点的出入度
int sta[maxn],top=0;
map<int,map<int,bool>>vis;
int del[maxn];
//欧拉路径:通过图中每条边恰好一次的路径。
//(起点与终点不同时的判据)
//有向图:起点出度比入度多 1,终点入度比出度多 1,其余点出入度相等。
//无向图:起点和终点是奇度数,其余点偶度数。
//欧拉回路:起点和终点相同的欧拉路径。
//有向图:所有点出入度相同。
//无向图:所有点偶度数。
void dfs(int u){
for(int i=del[u];i<G[u].size();i=del[u]){
del[u]=i+1;
dfs(G[u][i]);
}
sta[++top]=u;
}
int read(){
int x=0,f=0,ch=getchar();
while(!isdigit(ch)){if(ch=='-')f=1;ch=getchar();}
while(isdigit(ch)){x=x*10+ch-'0';ch=getchar();}
return f?-x:x;
}
int main(){
int n=read(),m=read();
for(int i=1;i<=m;i++){
int u=read(),v=read();
out[u]++;in[v]++;
G[u].push_back(v);
}
for(int i=1;i<=n;i++)
sort(G[i].begin(),G[i].end());
int st=0,ed=0,flag=0;
for(int i=1;i<=n;i++){
if(in[i]==out[i]) continue;
else if(in[i]==out[i]-1){
if(!st) st=i;
else flag=1;//已经有起点了
}
else if(in[i]-1==out[i]){
if(!ed) ed=i;
else flag=1;//已经有终点了
}
else flag=1;//出现了出度和入度相差超过2的结点
}
if(!st&&!ed) st=ed=1;
else if(!st||!ed) flag=1;//没找到起点或者终点
if(flag)//没有欧拉路径
printf("No\n");
else{
dfs(st);
for(int i=top;i;i--)
printf("%d ",sta[i]);
}
system("pause");
return 0;
}