歐拉路徑和歐拉回路

本文主要內容是歐拉路徑和歐拉回路

文章目錄


概念

  • 歐拉路徑:不重複地經過每條邊的路徑
  • 歐拉回路:不重複地經過每條邊的迴路
  • 歐拉圖:存在歐拉回路的圖
  • 半歐拉圖:存在歐拉路徑的圖

定理

  • 無向圖爲歐拉圖的充要條件:連通且沒有奇數度數的點(簡稱奇點)。
  • 無向圖爲半歐拉圖的充要條件:連通且奇點數爲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. ↩︎

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