首先,欧拉路分为欧拉回路和欧拉通路。
欧拉回路
顾名思义,就是一笔画完了后要回到起点。
无向图
所有点的度数都为偶数。
有向图
所有点的入度等于出度。
(入度:有向图中某点作为图中边的 终点 的次数之和)
(出度:有向图中某点作为图中边的 起点 的次数之和)
欧拉通路
也是一笔画,但不用回到起点。
另外,欧拉回路必定是欧拉通路。
无向图
起点和终点的度数为奇数。
其余点的度数为偶数。
有向图
起点的出度比入度大1。
终点的入度比出度大1。
其余节点的入度等于出度。
一笔画问题
判断一个有(无)向图需要几笔画完。
无向图
度数为奇数的点的个数除以2。
(度数为奇数的点的度数不可能为奇数)
有向图
累加所以入度比出度大的点的入度减出度的差即为答案。
(出度也一样)
例题
(WOJ3853)
欧拉回路
描述
有一天一位灵魂画师画了一张图,现在要你找出欧拉回路,即在图中找一个环使得每条边都在环上出现恰好一次。
一共两个子任务:
这张图是无向图。(50 分)
这张图是有向图。(50 分)
输入
第一行一个整数 tt,表示子任务编号。t∈{1,2}t∈{1,2},如果 t=1t=1 则表示处理无向图的情况,如果 t=2t=2 则表示处理有向图的情况。
第二行两个整数 n,mn,m,表示图的结点数和边数。
接下来 mm行中,第ii行两个整数 vi,uivi,ui,表示第 ii 条边(从 11 开始编号)。保证1≤vi,ui≤n1≤vi,ui≤n。
如果 t=1t=1 则表示vivi到 uiui有一条无向边。
如果 t=2t=2 则表示 vivi到 uiui有一条有向边。
图中可能有重边也可能有自环。
输出
如果不可以一笔画,输出一行 NO。
否则,输出一行 YES,接下来一行输出一组方案。
如果 t=1t=1,输出 mm个整数 p1,p2,…,pmp1,p2,…,pm。令 e=|pi|e=|pi|, 那么 ee 表示经过的第ii 条边的编号。如果 pipi为正数表示从 veve 走到 ueue ,否则表示从 ueue走到 veve。
如果 t=2t=2,输出 mm 个整数 p1,p2,…,pmp1,p2,…,pm。其中 pipi 表示经过的第 ii 条边的编号。
样例输入 1
1
3 3
1 2
2 3
1 3
样例输出 1
YES
1 2 -3
样例输入 2
2
5 6
2 3
2 5
3 4
1 2
4 2
5 1
样例输出 2
YES
4 1 3 5 2 6
提示
1≤n≤10^5
0≤m≤2×10^5
1≤n≤10^5
0≤m≤2×10^5
标签
UOJ117
题解
按上面讲的判断即可。
但需注意:
- 这个图可能不联通。
- 可能会有孤立点,没有边连向这个点,就相当于我们可以不用考虑这个点,因为欧拉回路是遍历完所有的边,而不是点。
- 注意用当前弧优化(int &i=first[x]),不然会Time Out(dfs完了后i就会变成0,所有要先存储一次)。
- 用ans数组来存储,而不是遍历到就输出,以免遭遇不测。
- 数组开小了也会Wrong Answer。
上代码:
#include<bits/stdc++.h>
using namespace std;
inline int read(){
int x=0;char c=getchar();
while(!isdigit(c))c=getchar();
while(isdigit(c)){x=(x<<3)+(x<<1)+(c^48);c=getchar();}
return x;
}
struct edge{
int u,v,nxt;
}e[400010];
int first[100010],cnt=1;
inline void add(int u,int v){
e[++cnt].u=u;e[cnt].v=v;
e[cnt].nxt=first[u];first[u]=cnt;
}
int t,n,m,din[100010],dout[100010];
bool vis[400010];
int ans[400010],tot=0;
void dfs1(int x){
for(int &i=first[x];i;i=e[i].nxt){
if(vis[i]||vis[i^1])continue;
int r=i/2,flag=i%2;
vis[i]=1;
dfs1(e[i].v);
if(flag)ans[++tot]=-r;
else ans[++tot]=r;
}
}
void dfs2(int x){
for(int &i=first[x];i;i=e[i].nxt){
if(vis[i])continue;
int r=i-1;
vis[i]=1;
dfs2(e[i].v);
ans[++tot]=r;
}
}
int main(){
t=read();n=read();m=read();
if(t==1){
for(int i=1;i<=m;i++){
int u,v;
u=read();v=read();
add(u,v);add(v,u);
din[u]++;din[v]++;
}
for(int i=1;i<=n;i++){
if(din[i]%2==1){
printf("NO");
return 0;
}
}
for(int i=1;i<=n;++i){//可能没有这个节点
if(first[i]){
dfs1(i);
break;
}
}
if(tot!=m){//可能不连通
printf("NO");
return 0;
}
printf("YES\n");
for(int i=m;i>=1;i--){
printf("%d ",ans[i]);
}
}
else{
for(int i=1;i<=m;i++){
int u,v;
u=read();v=read();
add(u,v);
din[v]++;dout[u]++;
}
for(int i=1;i<=n;i++){
if(din[i]!=dout[i]){
printf("NO");
return 0;
}
}
for(int i=1;i<=n;++i){//可能没有这个节点
if(first[i]){
dfs2(i);
break;
}
}
if(tot!=m){//可能不连通
printf("NO");
return 0;
}
printf("YES\n");
for(int i=m;i>=1;i--){
printf("%d ",ans[i]);
}
}
return 0;
}
。:.゚ヽ(。◕‿◕。)ノ゚.:。+゚