欧拉路的基础知识

一.欧拉路与欧拉回路的学习

定义

  • 欧拉路:从图的一个点出发遍历整张图,每条边通过且只通过一次
  • 欧拉回路:起点等于终点的欧拉路
  • 偶点:度为偶数的点
  • 奇点:度为奇数的点
  • 考查内容:是否有欧拉(回)路和打印欧拉(回)路

判断欧拉路和欧拉回路是否存在

  • 前提: 连通图。判断连通性问题可以用 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 (n2)/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;
}
  • 2
    点赞
  • 9
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值