一.欧拉路与欧拉回路的学习
定义
- 欧拉路:从图的一个点出发遍历整张图,每条边通过且只通过一次
- 欧拉回路:起点等于终点的欧拉路
- 偶点:度为偶数的点
- 奇点:度为奇数的点
- 考查内容:是否有欧拉(回)路和打印欧拉(回)路
判断欧拉路和欧拉回路是否存在
- 前提: 连通图。判断连通性问题可以用 dfs 或者并查集实现
对于无向连通图
- 如果图中的所有点均是偶点,则存在欧拉回路,任意点均可成为起点和终点。
- 如果只有两个奇点,则存在欧拉路。其中一个奇点是起点,另一个奇点是终点。
对于有向连通图
- 如果图中所有点入度和出度均相等,则存在欧拉回路。
- 如果只有一个点入度比出度大1,只有一个点出度比入度大1,剩下的点入度与出度均相等,则存在欧拉路。
输出一个欧拉回路
- 如果是输出随便一条欧拉回路,直接从起点跑,用栈存路径即可。
- 如果是输出一条最小字典序欧拉回路,则需使用邻接矩阵存图,这样每次都是走最小点。
邻接矩阵代码
#include<bits/stdc++.h>
using namespace std;
int n,g[1000][1000],chu[100000],stk[100000],top;
void dfs(int u) {
for(int i=1; i<=n; i++) {
if(g[u][i]) {
g[u][i]--;
g[i][u]--;
dfs(i);
}
}
stk[++top]=u;
}
int main() {
int m,u,v;
cin>>n>>m;
for(int i=1; i<=m; i++) {
cin>>u>>v;
g[u][v]++;
g[v][u]++;
}
dfs(1);
while(top)cout<<stk[top--]<<" ";
}
二.开始刷题
判断是否存在欧拉(回)路
例题1:n 个点的完全图的最长欧拉路径
- 题目描述: n 个点的一个完全图,每条边只能走一次,求最多可以经过多少条边。 n < = 1 e 9 n<=1e9 n<=1e9
- 问题分析: 答案是一个欧拉路,而且要让这条欧拉路尽可能长。考虑删除不属于欧拉路的边:一个欧拉路的条件是只有两个奇点或者没有奇点。如果 n 是奇数,则所有点均为偶点,无需删边;如果 n 是偶数,则所有点均为奇点,需要将 n-2 个点变成偶点,那么只需要删除 ( n − 2 ) / 2 (n-2)/2 (n−2)/2 条边就行。
例题2:建图,判断欧拉路径
- 题目描述: n 根棍子,每个棍子的头尾两边各有一种颜色 u i , v i u_i,v_i ui,vi 。问是否能将 n 根棍子串在一起,使得每两根挨着的棍子的相邻端颜色相同。
- 问题分析: 可以将颜色当成点,棍子当成边。那么问题就变成了,该图是否存在欧拉路径。
#include <bits/stdc++.h>
using namespace std;
const int N=5e5+10;
int du[N],fa[N];
unordered_map<string,int>m;
int find(int x){
if(x==fa[x])return fa[x];
else return fa[x]=find(fa[x]);
}
int main() {
int cnt=0;
string s,p;
for(int i=1; i<=500000; i++)fa[i]=i;
while(cin>>s>>p) {
if(m[s]==0)m[s]=++cnt;
if(m[p]==0)m[p]=++cnt;
du[m[s]]++;
du[m[p]]++;
if(find(m[s])!=find(m[p]))fa[find(m[s])]=find(m[p]);
}
int num=0;
for(int i=1; i<=cnt; i++) {
if(find(i)==i)num++;
}
if(num!=1)cout<<"Impossible";
else {
num=0;
for(int i=1; i<=cnt; i++) {
if(du[i]%2==1)num++;
}
if(num==0||num==2)cout<<"Possible";
else cout<<"Impossible";
}
return 0;
}
输出欧拉路径
例题1
- 题目描述: n 个点,m 条 边,构成一张图。已知存在欧拉路径,请将其打印。
- 问题分析: 只需要找到奇点作为起点,然后跑 dfs 即可。
#include<bits/stdc++.h>
using namespace std;
const int N=505;
int g[N][N],n,m,degree[N],stk[N*10],top;
void dfs(int u){
for(int i=1;i<=n;i++){
if(g[u][i]){
g[u][i]--;
g[i][u]--;
dfs(i);
}
}
stk[++top]=u;
}
int main(){
int u,v;
cin>>m;
for(int i=1;i<=m;i++){
cin>>u>>v;
g[u][v]++,g[v][u]++;
n=max(n,max(u,v));
degree[u]++,degree[v]++;
}
int s=1;
for(int i=1;i<=n;i++){
if(degree[i]%2){
s=i;
break;
}
}
dfs(s);
while(top)cout<<stk[top--]<<endl;
return 0;
}