[关闭]
@rebirth1120 2019-11-13T11:34:52.000000Z 字数 1684 阅读 970

欧拉回路 学习笔记

学习笔记


定义

是一张图
欧拉回路 : 图 中经过每条边一次并且仅一次的回路.
欧拉路径 : 图 中经过每条边一次并且仅一次的路径.
欧拉图 : 存在欧拉回路的图.
半欧拉图 : 存在欧拉路径但不存在欧拉回路的图.

定理与性质

以下的图中, 默认把孤立点删除, 因为这样不会影响原图是否为欧拉图.

定理1 : 无向图 为欧拉图, 当且仅当 为连通图且所有顶点的的度为偶数.
推论1 : 无向图 为半欧拉图, 当且仅当 为连通图, 且除了两个顶点的度为奇数外, 其他顶点的度为偶数.

定理2 : 有向图 为欧拉图, 当且仅当 为连通图且所有顶点的入度等于出度.
推论2 : 有线图 为半欧拉图, 当且仅当 为连通图, 且存在顶点 的出度比入度大 , 顶点 的入读比出度大 , 其他顶点的入度等于出度.

性质1 : 设 是欧拉图 的一个简单回路, 将 中的边从图 中删去得到一个新图 , 则 的每一个极大连通子图都存在一条欧拉回路.

性质2 : 设 是图 的两个没有公共边, 但有至少一个公共点的简单回路, 则可以将它们合并成一个新的简单回路 .

求欧拉回路

根据上面的定理, 我们已经可以判断欧拉图,
而求欧拉回路, 我们则需要用到上面的性质.

过程

  1. 找出图 中的一个简单回路, 并将它从图 中删去.
  2. 对图 的每一个极大连通子图重复上述的过程.
  3. 将图 的极大连通子图的欧拉回路合并, 得到图 的欧拉回路.

代码

欧拉回路
这个板子相对麻烦一点, 因为它要同时处理有向图和无向图的情况, 并且要求输出边的方案.

  1. #include<bits/stdc++.h>
  2. using namespace std;
  3. bool b;
  4. const int N=1e5+7;
  5. const int M=2e5+7;
  6. int ty,n,m,stk[M],top,frm[M],ans[M],ide[N],ode[N],blo[N],num;
  7. int lst[N],nxt[2*M],to[2*M],id[2*M],op[2*M],tot;
  8. bool vis[M],flag=1;
  9. void add(int x,int y,int k){ nxt[++tot]=lst[x]; to[tot]=y; id[tot]=k; lst[x]=tot; }
  10. void Euler_Circuit(){
  11. for(int i=1;i<=n;i++)
  12. if(lst[i]){ stk[++top]=i; break; }
  13. while(top){
  14. int u=stk[top],i=lst[u];
  15. while(i&&vis[abs(id[i])]) i=nxt[i];
  16. if(i){
  17. int v=to[i];
  18. stk[++top]=v;
  19. frm[top]=id[i];
  20. lst[u]=i;
  21. vis[abs(id[i])]=1;
  22. }
  23. else{
  24. ans[++ans[0]]=frm[top];
  25. top--;
  26. }
  27. }
  28. }
  29. bool a;
  30. int main(){
  31. // freopen("Euler.in","r",stdin);
  32. cin>>ty>>n>>m; int x,y;
  33. for(int i=1;i<=m;i++){
  34. scanf("%d%d",&x,&y);
  35. if(ty==1){
  36. add(x,y,i);
  37. add(y,x,-i);
  38. ide[x]++; ide[y]++;
  39. op[tot]=tot-1;
  40. op[tot-1]=tot;
  41. }
  42. else{
  43. add(x,y,i);
  44. ode[x]++; ide[y]++;
  45. }
  46. }
  47. for(int i=1;i<=n;i++)
  48. if(ty==1&&ide[i]%2){ flag=0; break; }
  49. else if(ty==2&&ide[i]!=ode[i]){ flag=0; break; }
  50. if(flag) Euler_Circuit();
  51. for(int i=1;i<=tot;i++)
  52. if(!vis[abs(id[i])]){ flag=0; break; }
  53. if(!flag) puts("NO");
  54. else{
  55. puts("YES");
  56. for(int i=ans[0]-1;i>=1;i--) printf("%d ",ans[i]); putchar('\n');
  57. }
  58. // cerr << (&a-&b)/1048576.0<<endl;
  59. return 0;
  60. }
添加新批注
在作者公开此批注前,只有你和作者可见。
回复批注