欧拉路径和欧拉回路

本文主要内容是欧拉路径和欧拉回路

文章目录


概念

  • 欧拉路径:不重复地经过每条边的路径
  • 欧拉回路:不重复地经过每条边的回路
  • 欧拉图:存在欧拉回路的图
  • 半欧拉图:存在欧拉路径的图

定理

  • 无向图为欧拉图的充要条件:连通且没有奇数度数的点(简称奇点)。
  • 无向图为半欧拉图的充要条件:连通且奇点数为2。(这两个点的分别是起点和终点)
  • 有向图为欧拉图的充要条件:基图连通且所有点入度等于出度。
  • 有向图为半欧拉图的充要条件:基图连通且存在一点s入度比出度少一,另一点t入度比出度多一,其余点入度等于出度。(s和t分别是起点和终点)

其他定理1

  • 当一连通无向图奇数度数的点数k>2时,需要k2\frac k2笔画成。(k一定为偶数)
  • 可以通过加边的方式将非欧拉图改成欧拉图。对于无向图,每个奇点加一度,最终加边数为2\frac{奇点数}2;对于有向图,每个点加对应数目的入度或出度使该点入度等于出度,最少加边数是Σ2\frac{\Sigma_{每个点}|入度数-出度数|}{2}

应用

1.判断一个无向图是否为欧拉图
题目:HDU1878欧拉回路
注意,一定要判是否连通

#include<cstdio>
#include<cstring>
#include<iostream>
#include<algorithm>
using namespace std;
const int N=1010;

int n, m;
int du[N], fa[N];

int getfa(int u)
{
	if(fa[u]==u) return u;
	return fa[u]=getfa(fa[u]);
}

void merge(int u, int v)
{
	int fu=getfa(u), fv=getfa(v);
	if(fu!=fv) fa[fu]=fv;
	return;
}

int main()
{
	while(~scanf("%d", &n) && n)
	{
		scanf("%d", &m);
		memset(du,0,sizeof(du));
		for(int i=1; i<=n; ++i) fa[i]=i;
		for(int i=0, u, v; i<m; ++i)
		{
			scanf("%d%d", &u, &v);
			du[u]++; du[v]++;
			merge(u,v);
		}
		bool ok=true;
		int t;
		// 找到一个有边相连的点的 fa 
		for(int i=1; i<=n; ++i)
			if(du[i])
				t=fa[i];
		// 欧拉图的条件是所有点的度数为偶数,且所有边连在一起  
		for(int i=1; i<=n; ++i)
			if(du[i]&&(du[i]&1||getfa(i)!=t)) ok=false;
		puts(ok?"1":"0");
	}
	return 0;
}

2.输出半欧拉图字典序最小的欧拉路径
洛谷P2731骑马修栅栏

先dfs,再倒序输出经过的每个点。

#include<cstdio>
#include<cstring>
#include<iostream>
#include<algorithm>
#include<queue>
using namespace std;
const int N=500, M=1030;

int m, sn;
int cnt[N+10][N+10], st[M], du[N+10];

void dfs(int u)
{
	for(int i=1; i<=N; ++i)
	{
		if(cnt[u][i]==0) continue; 
		cnt[u][i]--; cnt[i][u]--;
		dfs(i);
	}
	st[++sn]=u;
}

int main()
{
	scanf("%d", &m);
	int s=N;
	for(int i=0, u, v; i<m; ++i)
	{
		scanf("%d%d", &u, &v);
		cnt[u][v]++; cnt[v][u]++;
		du[u]++; du[v]++;
		s=min(s,u); s=min(s,v);
	}
	for(int i=1; i<=N; ++i)
		if(du[i]&1)
		{
			s=i;
			break;
		}
	dfs(s);
	for(int i=sn; i; --i)
		printf("%d\n", st[i]);
	return 0;
}

3.求无向图中的欧拉回路2

在图中任意找一个回路C
将C从图中删除
在残留图的各个极大连通分量中寻找欧拉回路
将各极大连通分量中的欧拉回路并到C上

我暂时还不会这个

4.一道有难度的例题
英文原题 Maximum Matching
中文翻译 最大匹配
英文题解

#include<cstdio>
#include<cstring>
#include<iostream>
#include<algorithm>
#include<vector>
using namespace std;
const int S=16, N=110;
#define compress(i,j) ((i)<(j)?(i)*4+(j):(j)*4+(i))

struct Edge
{
	int c1, val, c2, id;
	bool operator<(const Edge & t)const{ return val<t.val; }
}e[N<<1];

struct Node
{
	int to, val, id;
};

struct UnionFind
{
	int f, val;
}u[4];

vector<Node> V[4];
vector<Edge> E[S];

int n;
int cnt[4];
bool vis[N], have[4];

int findfa(int a)
{
	if(u[a].f==a) return a;
	return u[a].f=findfa(u[a].f);
}

void merge(int a, int b, int val)
{
	int fa=findfa(a), fb=findfa(b);
	if(fa!=fb) u[u[fa].f=fb].val+=u[fa].val+val;
	else u[fb].val+=val;
	return;
}

int getans(int i)
{
	int f1=findfa(i), maxv=0, numj=0;
	for(int i=0; i<4; ++i)
		if(findfa(i)==f1)
		{
			have[i]=true;
			maxv=max(maxv,u[i].val);
			if(cnt[i]&1) numj++;
		}
	if(numj==2||numj==0) return maxv;
	return 0;
}

int main()
{
	int ans=0;
	// input
	scanf("%d", &n);
	for(int i=1; i<=n; ++i)
	{
		int c1, val, c2, id;
		scanf("%d%d%d", &c1, &val, &c2);
		c1--; c2--;
		V[c1].push_back((Node){c2,val,i});
		V[c2].push_back((Node){c1,val,i});
		e[i]=(Edge){c1,val,c2,i};
		E[compress(c1,c2)].push_back(e[i]);
	}
	for(int i=0; i<S; ++i)
	{
		if(E[i].size())
		{
			sort(E[i].begin(),E[i].end());
		}
	}
	//solve
	for(int s=0; s<1<<S; ++s)
	{
		//initialization
		memset(vis,false,sizeof(vis));
		memset(cnt,0,sizeof(cnt));
		memset(have,false,sizeof(have));
		for(int i=0; i<4; ++i)
		{
			u[i].f=i; u[i].val=0;
		}
		//union find
		for(int i=0; i<S; ++i)
			if((s&(1<<i))&&E[i].size())
				vis[E[i][0].id]=1;
				
		for(int i=1; i<=n; ++i)
				if(!vis[e[i].id])
				{
					int a=e[i].c1, b=e[i].c2;
					merge(a,b,e[i].val);
					cnt[a]++; cnt[b]++;
				}
		// get ans
		for(int i=0; i<4; ++i)
			if(!have[i])
				ans=max(ans,getans(i));
	}
	printf("%d\n", ans);
	return 0;
}

最后,武汉加油,一定可以战胜疫情的!

2020.01.27


  1. 青君.欧拉回路与欧拉路径总结[DB/OL].2018-08-22 ↩︎

  2. 仇荣琦.欧拉回路性质与应用探究[DB/OL].2011-01-09. ↩︎

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章