欧拉路就是所有边都走一次,也只走一次。
欧拉回路就是能够回到起点,欧拉路径没有这么多要求。
算法本质是这样的:
从起点开始,尽可能地不去走桥(走完之后会把图分成两半),而去走其他边,这样的输出是欧拉路径。
但是判桥的过程较为麻烦,我们可以采取这样的手段。
如果起点开始有两条边,一条边是应该走的边,另一条是桥。如果我们采用
d
f
s
dfs
dfs的方式先遍历到底,直到无路可走的时候才加入答案栈中,我们容易知道的是最后无路可走的一定是最后一个点(不可能在之前输出,否则…就不存在这样的路径)每次都采用这样的手段,把无路可走的放在栈后面,有路可走的等到最后无路可走的时候再放上去。
最后即为答案。
因为常常这样的路径会导致递归栈占用过大,而且答案数组也可能会过大(放在递归里貌似占用递归栈)。
所以采用非递归的写法。
对于欧拉路径的判断呢:
首先考虑欧拉路径(两个奇点,其他都是入度出度相等)
其次考虑欧拉回路(因为可能不连通,所有入度出度都相等并且起点出度>0,可能存在多个欧拉环的情况,要特殊判边)
这是模板(已通过超坑题目验证)
#include<bits/stdc++.h>
#define FOR(i,a,b) for(int i=a;i<=b;i++)
using namespace std;
int n,m;
int dfs_st[10000500],dfn=0;
int ans[10000500],cnt=0,num=0;
vector<int>G[1000050];
int cur[1000050];
int ind[1000050],out[1000050];
void dfs(int x){
FOR(i,1,n)sort(G[i].begin(),G[i].end());
dfs_st[++dfn]=x;
memset(cur,-1,sizeof(cur));
while(dfn>0){
int u=dfs_st[dfn];
int complete=1;
for(int i=cur[u]+1;i<G[u].size();i++){
int v=G[u][i];
num++;
dfs_st[++dfn]=v;
cur[u]=i;
complete=0;
break;
}
if(complete)ans[++cnt]=u,dfn--;
}
}
bool check(int &start){
int l=0,r=0,mid=0;
FOR(i,1,n){
if(ind[i]==out[i]+1)l++;
if(out[i]==ind[i]+1)r++,start=i;
if(ind[i]==out[i])mid++;
}
if(l==1&&r==1&&mid==n-2)return true;
l=1;
FOR(i,1,n)if(ind[i]!=out[i])l=0;
if(l){
FOR(i,1,n)if(out[i]>0){
start=i;
break;
}
return true;
}
return false;
}
int main(){
cin>>n>>m;
FOR(i,1,m){
int x,y;scanf("%d%d",&x,&y);
G[x].push_back(y);
ind[y]++,out[x]++;
}
int start=-1,ok=true;
if(check(start)){
dfs(start);
if(num!=m){
puts("What a shame!");
return 0;
}
for(int i=cnt;i>=1;i--)
printf("%d ",ans[i]);
puts("");
}
else puts("What a shame!");
}