有向图欧拉路径求解

欧拉路径

定义

经过图中每条恰好 \(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\),则欧拉路径不存在。

构造

luogu P7771 【模板】欧拉路径

求有向图字典序最小的欧拉路径。


字典序最小,将边按终点排序后构造即可。

考虑访问所有边,并记录点的编号,来构造欧拉路径。

\(\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;
}
posted @ 2025-11-26 11:59  TH911  阅读(4)  评论(0)    收藏  举报