有向图欧拉路径求解
欧拉路径
定义
经过图中每条边恰好 \(1\) 次的路径。
同时,还定义了:
- 欧拉回路:起点、终点相同。
- 欧拉图:存在欧拉回路的图。
- 半欧拉图:存在欧拉路径,不存在欧拉回路的图。
性质
记点 \(x\) 的入度为 \(\textit{in}_x\),出度为 \(\textit{out}_x\)。
欧拉路径存在,当且仅当 \(\textit{in}_x\neq\textit{out}_x\) 的 \(x\) 为:
-
\(0\) 个,此时存在欧拉回路,任意点均可作为起点/终点。
-
\(2\) 个,设起点、终点为 \(s,t\),有 \(\textit{in}_s+1=\textit{out}_s,\textit{in}_t=\textit{out}_t+1\)。
若不存在合法的 \(s,t\),则欧拉路径不存在。
构造
求有向图字典序最小的欧拉路径。
字典序最小,将边按终点排序后构造即可。
考虑访问所有边,并记录点的编号,来构造欧拉路径。
设 \(\textit{vis}_{\textit{id}},\textit{last}_x\) 分别表示边 \(\textit{id}\) 是否走过,\(x\) 的 \(1\sim\textit{last}_x\) 号出边已经处理过。
那么对于边 \((x,v_i)\),如果 \(i\leq\textit{last}_x\) 或者 \(\textit{vis}_{\textit{id}}=\mathrm{true}\),都需要跳过。
否则就走到 \(v_i\),继续 DFS。
记录答案需要在 DFS 完子节点之后记录,最后倒序输出。(因为只有在 DFS 完所有出边后,才能确定当前节点在最终路径中的位置。)
void dfs(int x,vector<int>&ans){
static int vis[M+1],last[N+1];
for(int i=0;i<g[x].size();i=max(i,last[x])+1){
auto [v,id]=g[x][i];
if(!vis[id]){
vis[id]=1;
last[x]=i;
dfs(v,ans);
}
}
ans.push_back(x);
}
AC 代码
//#include<bits/stdc++.h>
#include<algorithm>
#include<iostream>
#include<cstring>
#include<iomanip>
#include<cstdio>
#include<string>
#include<vector>
#include<cmath>
#include<ctime>
#include<deque>
#include<queue>
#include<stack>
#include<list>
using namespace std;
constexpr const int N=1e5,M=2e5;
int n;
vector<pair<int,int>>g[N+1];
void dfs(int x,vector<int>&ans){
static int vis[M+1],last[N+1];
for(int i=0;i<g[x].size();i=max(i,last[x])+1){
auto [v,id]=g[x][i];
if(!vis[id]){
vis[id]=1;
last[x]=i;
dfs(v,ans);
}
}
ans.push_back(x);
}
void Solve(){
static int in[N+1],out[N+1];
for(int i=1;i<=n;i++){
for(auto [j,id]:g[i]){
in[j]++;
out[i]++;
}
}
int cnt=0,s=0,t=0;
for(int i=1;i<=n;i++){
if(in[i]!=out[i]){
cnt++;
if(in[i]+1==out[i]){
s=i;
}else if(in[i]==out[i]+1){
t=i;
}
}
}
vector<int>ans;
if(cnt==0){
dfs(1,ans);
}else if(cnt==2&&s&&t){
dfs(s,ans);
}else{
cout<<"No\n";
return;
}
reverse(ans.begin(),ans.end());
for(int i:ans){
cout<<i<<' ';
}
}
int main(){
/*freopen("test.in","r",stdin);
freopen("test.out","w",stdout);*/
ios::sync_with_stdio(false);
cin.tie(0);cout.tie(0);
int m;
cin>>n>>m;
for(int i=1;i<=m;i++){
int u,v;
cin>>u>>v;
g[u].push_back({v,i});
}
for(int i=1;i<=n;i++){
sort(g[i].begin(),g[i].end());
}
Solve();
cout.flush();
/*fclose(stdin);
fclose(stdout);*/
return 0;
}

浙公网安备 33010602011771号