https://loj.ac/problem/10105
题目描述
两个任务:\(t=1\)时,求无向图是否存在欧拉回路及其方案;\(t=2\)时,求有向图是否存在欧拉回路及其方案。
思路
对于无向图,存在欧拉回路的条件是所有节点的度均为偶数;对于有向图,存在欧拉回路的条件是原图的基图(忽略原图边方向的图)连通,且所有节点的如度等于出度。接下来考虑如何求一条欧拉回路。
我们考虑一条欧拉回路必定是由几个简单环构成的,所以我们直接沿每条边走,如果走成一条环就不再走这条边,从其他变开始走,最后合并起来的环就一定是欧拉回路的一种方案。因此对于任意一个点开始\(dfs\)即可。不过由于我们会重复访问很多次同一节点,时间复杂度可能会变为\(O(N×M)\),所以我们考虑走过这条边就把这条边删去,代码实现时在\(i=head[u]\)改为\(i=\)&\(head[u]\)即可。
代码
#include <bits/stdc++.h> using namespace std; const int N=1e5+10,M=4e5+10; void end() { printf("NO"); exit(0); } int nxt[M],to[M],tot=1,head[N]; void add_edge(int x,int y) { nxt[++tot]=head[x]; head[x]=tot; to[tot]=y; } int read() { int res=0,w=1; char ch=getchar(); while(ch<'0'||ch>'9'){if(ch=='-')w=-1;ch=getchar();} while(ch>='0'&&ch<='9'){res=(res<<3)+(res<<1)+ch-'0';ch=getchar();} return res*w; } int t; vector<int>ans; bool vis[M]; void dfs(int u) { // cout<<u<<':'<<endl; for(int &i=head[u];i;i=nxt[i]) { int v=to[i],c=((t==1)?i/2:i-1),f=i&1; if(vis[c])continue ; vis[c]=1; dfs(v); if(t==1)ans.push_back(f?-c:c); else ans.push_back(c); } } int in[N],out[N]; int main() { int n,m; t=read(); n=read();m=read(); for(int i=1;i<=m;i++) { int x=read(),y=read(); add_edge(x,y); if(t==1)add_edge(y,x); in[y]++;out[x]++; } if(t==1) { for(int i=1;i<=n;i++) if((in[i]+out[i])%2)end(); } else { for(int i=1;i<=n;i++) if(in[i]!=out[i])end(); } for(int i=1;i<=n;i++) if(head[i]) { dfs(i); break ; } // cout<<ans.size()<<endl; if(ans.size()!=m)end(); printf("YES\n"); for(int i=m-1;i>=0;i--) printf("%d ",ans[i]); }