欧拉路径(Hierholzer 算法)

有向图

https://www.luogu.com.cn/problem/P7771

题意概述

给定一个弱连通有向图,求字典序最小的欧拉路径。

思路

有向图判定是否存在欧拉路径:

1.删去孤立点(入度与出度均为 \(0\)),剩下的点形成的图弱连通。

2.如果所有点的入度 \(=\) 出度,存在欧拉回路,可以任取起点。

3.仅存在一个点出度 \(=\) 入度 \(+1\),该点作为起点;仅存在一个点入度 \(=\) 出度 \(+1\),该点作为终点;其他点入度 \(=\) 出度。

4.其他情况不存在欧拉路径。

由于要求字典序最小,需要对边集排序。

代码

//author:kzssCCC

#include <bits/stdc++.h>
using namespace std;
using ll = long long;


void solve(){
	int n,m;
	cin >> n >> m;

	vector<vector<int>> adj(n+1);
	vector<int> ing(n+1),oug(n+1);

	for (int i=0;i<m;i++){
		int u,v;
		cin >> u >> v;

		adj[u].push_back(v);
		ing[v]++,oug[u]++;
	}

	for (int i=1;i<=n;i++){
		sort(adj[i].begin(),adj[i].end());
	}

	int s=-1,t=-1;
	for (int i=1;i<=n;i++){
		if (ing[i]!=oug[i]){
			if (ing[i]+1==oug[i] && s==-1){
				s = i;
			}
			else if (ing[i]==oug[i]+1 && t==-1){
				t = i;
			}
			else{
				cout << "No" << '\n';
				return;
			}
		}
	}

	if ((s==-1)^(t==-1)){
		cout << "No" << '\n';
		return;
	}

	if (s==-1){
		for (int i=1;i<=n;i++){
			if (ing[i]>0){
				s = i;
				break;
			}		
		}
	}

	vector<int> res;
	vector<int> cur(n+1);

	function<void(int)> dfs = [&](int u){
		int len = adj[u].size();

		while (cur[u]<len){
			int v = adj[u][cur[u]++];
			dfs(v);
		}

		res.push_back(u);
	};

	dfs(s);
	reverse(res.begin(),res.end());

	for (auto& v:res){
		cout << v << ' ';
	}
	cout << '\n';
}

int main(){
	ios::sync_with_stdio(false);
	cin.tie(0);
	
	int t = 1;
	// cin >> t;
	while (t--) solve();

	return 0;
}

无向图

https://www.luogu.com.cn/problem/P2731

题意概述

给定一个连通无向图,求字典序最小的欧拉路径。

思路

无向图判定是否存在欧拉路径:

1.删去孤立点(入度与出度均为 \(0\)),剩下的点形成的图连通。

2.如果所有点度数均为偶数,存在欧拉回路,可以任取起点。

3.恰好存在 \(2\) 个度数为奇数的点,存在欧拉路径,两个点分别作为起点和终点。

4.其他情况不存在欧拉路径。

同样对边集排序。

实现上,由于为无向图,邻接表要需存边的序号以保证不走同样的边。

代码

//author:kzssCCC

#include <bits/stdc++.h>
using namespace std;
using ll = long long;


void solve(){
	const int n = 500;
	int m;
	cin >> m;

	vector<vector<pair<int,int>>> adj(n+1);
	vector<int> deg(n+1);

	for (int i=0;i<m;i++){
		int u,v;
		cin >> u >> v;

		adj[u].emplace_back(v,i);
		adj[v].emplace_back(u,i);

		deg[u]++,deg[v]++;
	}

	for (int i=1;i<=n;i++){
		sort(adj[i].begin(),adj[i].end());
	}

	int s = -1;
	for (int i=1;i<=n;i++){
		if (deg[i]&1){
			s = i;
			break;
		}
	}

	if (s==-1){
		for (int i=1;i<=n;i++){
			if (deg[i]>0){
				s = i;
				break;
			}
		}
	}

	vector<int> res;
	vector<int> cur(n+1);
	vector<bool> vis(m,false);

	function<void(int)> dfs = [&](int u){
		int len = adj[u].size();

		while (cur[u]<len){
			auto& [v,id] = adj[u][cur[u]++];

			if (!vis[id]){
				vis[id] = true;
				dfs(v);
			}
		}

		res.push_back(u);
	};

	dfs(s);
	reverse(res.begin(),res.end());
	for (auto& v:res){
		cout << v << '\n';
	}
}

int main(){
	ios::sync_with_stdio(false);
	cin.tie(0);
	
	int t = 1;
	// cin >> t;
	while (t--) solve();

	return 0;
}
posted @ 2026-05-07 12:33  kzssCCC  阅读(31)  评论(0)    收藏  举报