欧拉回路 欧拉路径
歐拉路徑(瞎)定義 : 如果有一條路徑使得能夠走完所有的邊且每一條邊經(jīng)過(guò)有且只有一次,這樣的路徑叫做歐拉路徑
歐拉回路定義 : 如果有從起點(diǎn)出發(fā)最后回到起點(diǎn)的一條路徑使得能夠走完所有的邊且每條邊經(jīng)過(guò)有且只有一次,稱(chēng)其為歐拉回路
根據(jù)定義,歐拉回路是歐拉路徑的一個(gè)子集,存在歐拉回路定存歐拉路徑,反之則不一定成立
半歐拉圖 : 有歐拉路徑而沒(méi)有歐拉回路的圖
歐拉圖 : 包含至少一個(gè)歐拉回路的圖
?
如何判斷一幅圖是否有歐拉路徑/回路? PS :?以下的歐拉路徑條件都是針對(duì)半歐拉圖來(lái)說(shuō)
① 有向圖情況
歐拉路徑 ==> 有且只有一個(gè)點(diǎn)的出度 - 入度 == 1、有且只有一個(gè)點(diǎn)的入度 - 出度 == 1、其余點(diǎn)的出入度相等
歐拉回路 ==> 所有點(diǎn)的出度 == 入度
② 無(wú)向圖情況
歐拉路徑 ==> 有且只有兩個(gè)點(diǎn)的度為奇數(shù)(起點(diǎn)、終點(diǎn))、其他點(diǎn)的度為偶數(shù)
歐拉回路 ==> 所有點(diǎn)的度都為偶數(shù)
?
以上只能判定路徑的有無(wú)、而要找到其中一條歐拉路徑/回路,有兩種算法
一種是 Fluery 算法、一種是 Hierhoizers 算法
Fluery 算法 : 略......、給個(gè)鏈接
Hierhoizers 算法 :?
此算法是基于 DFS 的路徑回復(fù)算法,前提條件是給其指定好起點(diǎn)
算法會(huì)自動(dòng)尋找歐拉回路、找不到的情況下會(huì)找到歐拉路徑
/* 開(kāi)始DFS遞歸函數(shù)(當(dāng)前頂點(diǎn) x):尋找與 x 相連的邊(x,v):刪除 (x,v)刪除 (v,x)///如果是無(wú)向圖的話DFS(v)將x插入到路徑棧中 */struct EDGE{ int v, nxt; bool used; }; ///鏈?zhǔn)较蚯靶沁吔Y(jié)構(gòu)體定義 stack<int> path; ///定義棧記錄頂點(diǎn)路徑void DFS(int x) {for(int i=Head[x]; i!=-1; i=Edge[i].nxt){int Eiv = Edge[i].v;if(!Edge[i].used){Edge[i].used = true;DFS(x);}}path.push(x); }?
例題 POJ 2337?Catenyms
以 26 個(gè)字母為頂點(diǎn)、以給出的單詞為邊,找出一條字典序最小的歐拉路徑就是答案
由于這里要字典序最小,基于我們尋找歐拉路徑的DFS算法,所以在進(jìn)行建圖的時(shí)候
最好將單詞進(jìn)行字典序排序再來(lái)插入到鄰接表中即可達(dá)到這個(gè)目的
#include<bits/stdc++.h> using namespace std; const int maxn = 1e3 + 10; struct EDGE{ int v, nxt, id; bool used; }Edge[maxn<<2]; int Head[30], cnt, N; int IN[30], OUT[30]; int St; int ans[maxn<<2], len; string str[maxn];inline void init() {memset(Head, -1, sizeof(Head));memset(IN, 0, sizeof(IN));memset(OUT, 0, sizeof(OUT));cnt = 0;St = 0x3f3f3f3f; }inline void AddEdge(int From, int To, int ID) {Edge[cnt].used = false;Edge[cnt].id = ID;Edge[cnt].v = To;Edge[cnt].nxt = Head[From];Head[From] = cnt++; }void DFS(int v, int id)///由于是要邊路徑而不是頂點(diǎn)路徑,所以要帶個(gè)邊參數(shù) {for(int i=Head[v]; i!=-1; i=Edge[i].nxt){if(!Edge[i].used){Edge[i].used = true;int Eiv = Edge[i].v;DFS(Eiv, Edge[i].id);}}if(id != -1)ans[len++] = id;// for(int i=Head[v]; i!=-1; i=Edge[i].nxt){///如果不像代邊的編號(hào)參數(shù),可以這樣寫(xiě) // if(!Edge[i].used){ ///也可以達(dá)到記錄邊路徑的作用 // Edge[i].used = true; // DFS(Edge[i].v); // ans[len++] = Edge[i].id; // } // } }int main(void) {int nCase;scanf("%d", &nCase);while(nCase--){init();scanf("%d", &N);for(int i=0; i<N; i++)cin>>str[i];sort(str, str+N);for(int i=N-1; i>=0; i--){///將邊從大的到小的插入,因?yàn)槭擎準(zhǔn)较蚯靶谴鎯?chǔ)int Len = str[i].length();int From = str[i][0] - 'a';int To = str[i][Len-1] - 'a';AddEdge(From, To, i);IN[To]++, OUT[From]++;St = min(To, min(St, From));///記錄一下DFS的起點(diǎn),對(duì)應(yīng)了有歐拉回路的情況 }int Not_equal, St_num, Des_num;Not_equal = St_num = Des_num = 0;for(int i=0; i<26; i++){if(!IN[i] && !OUT[i]) continue;if(IN[i] != OUT[i]) Not_equal++;if(OUT[i] - IN[i] == 1){St_num++;St = i;///此時(shí)已經(jīng)可以判定沒(méi)有歐拉回路了,改變起點(diǎn),將出度多的作為起點(diǎn)}else if(IN[i] - OUT[i] == 1)Des_num++;}if(Not_equal > 0){///如果有點(diǎn)的出入度不想等if(!(Not_equal == 2 && St_num == 1 && Des_num == 1)){///并沒(méi)有歐拉路徑puts("***");continue;}}len = 0;DFS(St, -1);///恢復(fù)歐拉路徑if(len != N){puts("***");continue;}for(int i=len-1; i>=0; i--){if(ans[i] == -1) continue;cout<<str[ans[i]];if(i > 0) putchar('.');else puts("");}}return 0; } /* 2 6 aloha arachnid dog gopher rat tiger 3 oak maple elm */ View Code?
轉(zhuǎn)載于:https://www.cnblogs.com/LiHior/p/8747203.html
總結(jié)
- 上一篇: 自制宿舍门禁,微信小程序蓝牙控制,比指纹
- 下一篇: bzoj1233 单调队列优化dp