1. 程式人生 > >無向圖求尤拉路徑,迴路 模板(Hierholzer 演算法)

無向圖求尤拉路徑,迴路 模板(Hierholzer 演算法)

定義:

歐拉回路:每條邊恰好只走一次,並能回到出發點的路徑

尤拉路徑:經過每一條邊一次,但是不要求回到起始點

歐拉回路存在性的判定:

無向圖
每個頂點的度數都是偶數,則存在歐拉回路。

有向圖
每個節頂點的入度都等於出度,則存在歐拉回路。

尤拉路徑存在性的判定:

有向圖 : 圖連通,當且僅當該圖所有頂點數的度數為0,或者一個頂點的度數為1,另一個頂點的度數為-1,其他頂點的度數為0。

無向圖:圖連通,當且僅當該圖所有頂點的度數為偶數,或者除了兩個度數為奇數外其餘的全是偶數。

混合圖(有的邊是單向的,有的邊是無向的。常被用於比喻城市裡的交通網路有的路是單行道,有的路是雙行道):

找到一個給每條無向的邊定向的策略,使得每個頂點的入度等於出度,這樣就能轉換成上面第二種情況。

const int MAXN = 1005;

int G[MAXN][MAXN];//存圖 
int cnt[MAXN];//存每個點度的奇偶性 
int N,M;//點個數,邊條數 
stack<int> S;//存路徑 

void dfs(int u){
    for(int v=1; v<=N; v++)
        if(G[u][v]){
            G[u][v]-=1;
            G[v][u]-=1;
            dfs(v);
            //不用恢復邊!
        }
    S.push(u);//出棧時記錄
}

inline void Print(){//輸出路徑 
	if(!S.empty()){
	    printf("%d",S.top());
	    S.pop();
	} 
	while(!S.empty()){
	    printf(" %d",S.top());
	    S.pop();
	}
	printf("\n");
}

inline void init(){
	memset(cnt,0,sizeof cnt);
	memset(G,0,sizeof G);
}

int main(){
    while(scanf("%d %d",&N,&M) == 2){
    	init();
    	int u,v;
	    for(int i=1 ; i<=M ; ++i){
	        scanf("%d %d",&u,&v);
	        G[u][v] += 1;
	        G[v][u] += 1;
	        cnt[u] ^= 1;//利用了異或運算,0表示度為偶數,1表示度為奇數。
	        cnt[v] ^= 1;
	    }
	    for(u=1; u<=N ; ++u){//注意判斷圖是否從1點開始 
	        if(cnt[u]) break;
	    }
	    if(u == N+1) dfs(1);//都為偶節點,從隨便一個開始都行 
	    else dfs(u);//從奇節點開始 
	    Print();
	}
   
    return 0;
}