歐拉回路---知識點詳解


歐拉通路: 通過圖中每條邊且只通過一次,並且經過每一頂點的

歐拉回路: 通過圖中每條邊且只通過一次,並且經過每一頂點的

有向圖的基圖:忽略有向圖所有邊的方向,得到的無向圖稱為該有向圖的基圖。 

無向圖

  設G是連通無向圖,則稱經過G的每條邊一次並且僅一次的路徑為歐拉通路

 如果歐拉通路是回路(起點和終點是同一個頂點),則稱此回路是歐拉回路

  具有歐拉回路的無向圖G成為歐拉圖

有向圖

(1)設D是有向圖,D的基圖連通,則稱經過D的每條邊一次並且僅有一次的有向路徑為 有向歐拉通路

(2)如果有向歐拉通路是有向回路,則稱此有向回路為  有向歐拉回路

(3)具有有向歐拉回路的圖D稱為有向歐拉圖

定理

 無向圖G存在歐拉通路的充要條件是:G為連通圖,並且G僅有兩個奇度結點(度數為奇數的頂點)或者無奇度結點。

推論

(1) 當G是僅有兩個奇度結點的連通圖時,G的歐拉通路必以此兩個結點為端點;

(2)當G是無奇度結點的連通圖時,G必有歐拉回路

(3)G為歐拉圖(存在歐拉回路)的充分必要條件是  G為無奇度結點的連通圖

 

(有向圖) 定理

有向圖D存在歐拉通路的充要條件是:D為有向圖,D的基圖連通,並且所有頂點的出度與入度相等;或者  除兩個頂點外,其余頂點的出度與入度都相等,而這兩個頂點中一個頂點的出度與入度之差為1,另一個頂點的出度與入度之差為-1.

推論

(1)當D除出、入度之差為1,-1的兩個頂點之外,其余頂點的出度與入度相等時,D的有向歐拉通路必以出、入度之差為1的頂點作為始點,以出、入度之差為-1的頂點作為終點。

(2)當D的所有頂點的出、入度都相等時,D中存在有向歐拉回路。

(3)有向圖D為有向歐拉圖的充要條件是  D的基圖為連通圖,並且所有頂點的出、入度都相等。

 

 

歐拉回路的求解

兩種方法:(1)DFS搜索  (Fleury)佛羅萊算法

(1)DFS搜索 思想求解歐拉回路的思路為:利用歐拉定理判斷出一個圖存在歐拉通路或歐拉回路后,選擇一個正確的起始頂點,用DFS算法遍歷所有的邊(每條邊只遍歷一次),遇到走不通就回退。在搜索前進方向上將遍歷過的邊按順序記錄下來。這組邊的排列就組成了一條歐拉通路或回路。

(2) (Fleury)佛羅萊算法

設G為一個無向歐拉圖,求G中一條歐拉回路的算法如下:

(1) 任取G中一頂點v0,令P0=v0;

(2)假設沿Pi=v0e1v1e2v2......eivi走到頂點vi,按下面方法從E(G)-{e1,e2,...,ei}中選ei+1。

        ei+1與vi相關聯

        除非無別的邊可供選擇,否則ei+1不應該是Gi=G-{e1,e2,...,ei}中的橋。

(3)當(2)不能再進行時算法停止。

        可以證明的是,當算法停止時,所得到的簡單回路Pm=v0e1v1e2v2......emvm,(vm=v0)為G中一條歐拉回路。

 

備注知識:

  設無向圖G(V,E)為連通圖,若邊集E1屬於E,在圖G中刪除E1中所有的邊后得到的子圖是不連通的,而刪除了E1的任一真子集后得到的子圖是連通圖,則稱E1是G的一個割邊集。若一條邊構成一個割邊集,則稱該邊為割邊,或

          

 

//歐拉路徑的輸出(此圖為無向圖)
#include<iostream>
using namespace std;
#define M 200
struct stack
{
	int top,node[M];
}s;             //頂點的棧結構
int Edge[M][M]; //鄰接矩陣
int n;          //頂點個數

void dfs(int x)   //這里的深度優先跟標准版有所區別,即不需要回溯
{
	s.top++;
	s.node[s.top]=x;   //將即將要擴展的結點壓入棧中
	for(int i=0;i<n;i++)
	{
		if(Edge[i][x]) //如果該節點還存在邊
		{
			Edge[i][x]=0;  
			Edge[x][i]=0;  //刪除該邊,然后搜索另一結點
			dfs(i);
			break;
		}
	}
}

void Fleury(int x)    //對頭節點使用Fleury算法 查找歐拉路徑
{
	s.top=0;
	s.node[s.top]=x;
	while(s.top>=0)
	{
		int flag=0;  //記錄當前結點是否有邊可以擴展
		for(int i=0;i<n;i++)
		{
			if(Edge[i][s.top])
			{
				flag=1;
				break;
			}
		}
		if(!flag)
		{
			cout<<s.node[s.top]+1<<" "; //記錄時是從0--n-1,所以應該加1
			s.top--;                    //結點輸出了,此結點出棧
		}
		else
		{
			s.top--;              //因為dfs處理時,需要先進棧,所以這里要先出棧,然后再進棧
			dfs(s.node[s.top+1]); //處理那個結點
		}
	}
	cout<<endl;
}

int main()
{
	int m,s,t;            //邊數,讀入的邊的起點和終點
	int degree,num,start; //每個頂點的度、基度頂點個數、歐拉回路的起點
	cin>>n>>m;            //n---頂點數  m---邊數
	memset(Edge,0,sizeof(Edge));
	for(int i=0;i<n;i++)
	{
		cin>>s>>t;
		Edge[s-1][t-1]=1;
        Edge[t-1][s-1]=1;
	}
	num=0;
	start=0;   //如果存在奇度頂點,則從奇度頂點出發,否則從頂點0出發
	for(int i=0;i<n;i++)
	{
		degree=0;
		for(int j=0;j<n;j++)
			degree+=Edge[i][j];
		if(degree%2) 
		{
			num++;
			start=i;
		}
	}
	if(num==0||num==2) Fleury(start);
	else cout<<"No Euler path"<<endl;
	return 0;
}

  


免責聲明!

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



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