@rebirth1120
2019-11-13T03:34:52.000000Z
字数 1684
阅读 1263
学习笔记
设 是一张图
欧拉回路 : 图 中经过每条边一次并且仅一次的回路.
欧拉路径 : 图 中经过每条边一次并且仅一次的路径.
欧拉图 : 存在欧拉回路的图.
半欧拉图 : 存在欧拉路径但不存在欧拉回路的图.
以下的图中, 默认把孤立点删除, 因为这样不会影响原图是否为欧拉图.
定理1 : 无向图 为欧拉图, 当且仅当 为连通图且所有顶点的的度为偶数.
推论1 : 无向图 为半欧拉图, 当且仅当 为连通图, 且除了两个顶点的度为奇数外, 其他顶点的度为偶数.
定理2 : 有向图 为欧拉图, 当且仅当 为连通图且所有顶点的入度等于出度.
推论2 : 有线图 为半欧拉图, 当且仅当 为连通图, 且存在顶点 的出度比入度大 , 顶点 的入读比出度大 , 其他顶点的入度等于出度.
性质1 : 设 是欧拉图 的一个简单回路, 将 中的边从图 中删去得到一个新图 , 则 的每一个极大连通子图都存在一条欧拉回路.
性质2 : 设 是图 的两个没有公共边, 但有至少一个公共点的简单回路, 则可以将它们合并成一个新的简单回路 .
根据上面的定理, 我们已经可以判断欧拉图,
而求欧拉回路, 我们则需要用到上面的性质.
欧拉回路
这个板子相对麻烦一点, 因为它要同时处理有向图和无向图的情况, 并且要求输出边的方案.
#include<bits/stdc++.h>using namespace std;bool b;const int N=1e5+7;const int M=2e5+7;int ty,n,m,stk[M],top,frm[M],ans[M],ide[N],ode[N],blo[N],num;int lst[N],nxt[2*M],to[2*M],id[2*M],op[2*M],tot;bool vis[M],flag=1;void add(int x,int y,int k){ nxt[++tot]=lst[x]; to[tot]=y; id[tot]=k; lst[x]=tot; }void Euler_Circuit(){for(int i=1;i<=n;i++)if(lst[i]){ stk[++top]=i; break; }while(top){int u=stk[top],i=lst[u];while(i&&vis[abs(id[i])]) i=nxt[i];if(i){int v=to[i];stk[++top]=v;frm[top]=id[i];lst[u]=i;vis[abs(id[i])]=1;}else{ans[++ans[0]]=frm[top];top--;}}}bool a;int main(){// freopen("Euler.in","r",stdin);cin>>ty>>n>>m; int x,y;for(int i=1;i<=m;i++){scanf("%d%d",&x,&y);if(ty==1){add(x,y,i);add(y,x,-i);ide[x]++; ide[y]++;op[tot]=tot-1;op[tot-1]=tot;}else{add(x,y,i);ode[x]++; ide[y]++;}}for(int i=1;i<=n;i++)if(ty==1&&ide[i]%2){ flag=0; break; }else if(ty==2&&ide[i]!=ode[i]){ flag=0; break; }if(flag) Euler_Circuit();for(int i=1;i<=tot;i++)if(!vis[abs(id[i])]){ flag=0; break; }if(!flag) puts("NO");else{puts("YES");for(int i=ans[0]-1;i>=1;i--) printf("%d ",ans[i]); putchar('\n');}// cerr << (&a-&b)/1048576.0<<endl;return 0;}
