歐拉圖


定義

通過圖中所有邊恰好一次且行遍所有頂點的通路稱為歐拉通路。

通過圖中所有邊恰好一次且行遍所有頂點的回路稱為歐拉回路。

具有歐拉回路的無向圖或有向圖稱為歐拉圖。

具有歐拉通路但不具有歐拉回路的無向圖或有向圖稱為半歐拉圖。

有向圖也可以有類似的定義。

非形式化地講,歐拉圖就是從任意一個點開始都可以一筆畫完整個圖,半歐拉圖必須從某個點開始才能一筆畫完整個圖。

性質

歐拉圖中所有頂點的度數都是偶數。

\(G\) 是歐拉圖,則它為若干個環的並,且每條邊被包含在奇數個環內。

判別法

對於無向圖 \(G\) ,

\(G\) 是歐拉圖的充要條件是 \(G\) 聯通,所有點的度數為偶數 ;

\(G\) 是半歐拉圖的充要條件是 \(G\) 聯通,只可能有 \(0/2\) 個點的度數為奇數 .

對於有向圖 \(G\) ,

\(G\) 是歐拉圖的充要條件是 \(G\) 聯通,所有點處於同一個強連通分塊里面,每個點的入度和出度相同 .

\(G\) 是半歐拉圖的充要條件是

  • \(G\) 中的所有邊視為無向邊,此時所有點處於同一個聯通塊中 .
  • 最多存在一個頂點 \(d^+(u)-d^-(u)=1\)
  • 最多存在一個頂點 \(d^-(u)-d^+(u)=1\)
  • 其余所有點的出度等於入度

歐拉圖的代碼實現

版子題,uoj #117. 歐拉回路 .

因為歐拉圖是很多個環的並 .

所以,對於每一個環,都可以輕松定下訪問的方向 .

此時,考慮如何將兩個環合並,首先,這兩個環能合並,必須要有點同時處於這兩個環上,此時,這兩個環的遍歷方案一定能被合並 .

dfs 的時候當前點 \(u\) 考慮直接找到一條沒有被訪問的邊 \((u,v)\) ,dfs 下去,肯定會在某個點再次訪問到 \(u\) ,此時,回溯的路徑一定構成一個歐拉回路 ( 一定是在 dfs 之后把 \(u\) 計入答案序列中 ) .

時間復雜度和空間復雜度都為 \(O(n+m)\) . 要加弧優化 . 不然會退化成 \(O(nm)\) .

#include<bits/stdc++.h>
using namespace std;
inline int rd(){
	char ch=getchar();
	while(ch<'0'||ch>'9')ch=getchar();
	int res=0;
	while(ch>='0'&&ch<='9'){
		res=(res<<3)+(res<<1)+ch-'0';
		ch=getchar();
	}
	return res;
}
inline void pr(int res){
	if(res==0){
		putchar('0');
		return;
	}
	int a[10],len=0;
	while(res>0){
		a[len++]=res%10;
		res/=10;
	}
	for(int i=len-1;i>=0;i--)
		putchar(a[i]+'0');
}
int type;
int n,m;
vector<pair<int,int> >g[100010];
int iter[100010];
int deg[100010];
bool vis[200010];
int mark[100010];
stack<int>s;
namespace undirected{
	void dfs(int x){
		mark[x]++;
		for(int &i=iter[x];i<(int)g[x].size();i++){
			int to=g[x][i].first,id=g[x][i].second;
			if(vis[abs(id)])continue;
			vis[abs(id)]=true;
			dfs(to);
			s.push(id);
		}
	}
	void work(){
		n=rd();m=rd();
		for(int i=1;i<=m;i++){
			int u=rd()-1,v=rd()-1;
			deg[u]++;
			deg[v]++;
			mark[u]=mark[v]=1;
			g[u].push_back(make_pair(v,i));
			g[v].push_back(make_pair(u,-i));
		}
		for(int i=0;i<n;i++){
			if(deg[i]&1){
				puts("NO");
				return;
			}
		}
		for(int i=0;i<n;i++){
			if(mark[i]==1){
				dfs(i);
				break;
			}
		}
		for(int i=0;i<n;i++){
			if(mark[i]==1){
				puts("NO");
				return;
			}
		}
		puts("YES");
		while(!s.empty()){
			if(s.top()<0)putchar('-');
			pr(abs(s.top()));
			putchar(' ');
			s.pop();
		}
		putchar('\n');
	}
}
namespace directed{
	void dfs(int x){
		mark[x]++;
		for(int &i=iter[x];i<(int)g[x].size();i++){
			int to=g[x][i].first,id=g[x][i].second;
			if(vis[id])continue;
			vis[id]=true;
			dfs(to);
			s.push(id);
		}
	}
	void work(){
		n=rd();m=rd();
		for(int i=1;i<=m;i++){
			int u=rd()-1,v=rd()-1;
			deg[u]++;
			deg[v]--;
			mark[u]=mark[v]=1;
			g[u].push_back(make_pair(v,i));
		}
		for(int i=0;i<n;i++){
			if(deg[i]!=0){
				puts("NO");
				return;
			}
		}
		for(int i=0;i<n;i++){
			if(mark[i]==1){
				dfs(i);
				break;
			}
		}
		for(int i=1;i<n;i++){
			if(mark[i]==1){
				puts("NO");
				return;
			}
		}
		puts("YES");
		while(!s.empty()){
			pr(s.top());
			putchar(' ');
			s.pop();
		}
		putchar('\n');
	}
}
int main(){
	type=rd();
	if(type==1)undirected::work();
	else directed::work();
	return 0;
}
/*inline? ll or int? size? min max?*/

題目

1. cf1610f Mashtali: a Space Oddysey

這道題重點不在於歐拉回路,而是在於想到可以縮邊,此時可以用歐拉回路來縮邊 . 題解


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM