1. 程式人生 > >歐拉回路&【洛谷習題】無序字母對

歐拉回路&【洛谷習題】無序字母對

就是 遞歸 ref class 刪除 如果 相等 pre 出發

首先非常痛心疾首地說一句,歐拉回路自己之前只是看過代碼,知道思想,從來沒有親手實現過,所以,,,傷亡慘重!!!

歐拉回路是一個非常有意思的圖論模型,因為偉大的數學家歐拉(euler)而得名。傳說,曾經人們沈迷於一個七橋問題,想找出一種走法不重復地經過七座橋(具體請自行了解)。歐拉指出了不存在這樣的走法,並由此歸結出了“一筆畫問題”。用圖論的語言來說,就是找一條路徑不重復地走過所有的邊。

實際上,從一個點出發,不重復地經過所有的邊,這叫做歐拉道路;如果這條路徑起點和終點相同,才稱為歐拉回路。另外,如果一個圖存在歐拉道路,那麽稱為半歐拉圖,如果一個圖存在歐拉回路,稱為歐拉圖。

對於無向圖,存在歐拉道路的條件是只有兩個或不存在奇點(度為奇數的點),存在歐拉回路的條件是不存在奇點。對於有向圖,存在歐拉道路的條件是只有兩個點的入度和出度不相同,並且其中一個點(起點)的出度比入度大1,另一個點(終點)的入度比出度大1,或者所有點的入度和出度都相等,存在歐拉回路的條件是所有點的入度和出度都相等。當然圖必須是連通的。

尋找歐拉道路或者歐拉回路是比較簡單的,可以使用DFS。起點的確定也需要註意,如果找歐拉道路,必須找到相應的起點,而歐拉回路任選一個點作為起點即可。

技術分享圖片
1 void euler(int u) {
2     for(int v=1;v<=n;++v)
3 if(G[u][v]) { 4 G[u][v]=G[v][u]=0; //有向圖則改為G[u][v]=0; 5 euler(v); 6 } 7 ans.push(u); 8 }
尋找歐拉道路或歐拉回路(無向圖)

需要註意的是,我們此處標記的是邊(或者刪除邊)。因為歐拉道路或歐拉回路是可以一口氣走到結束的,所以上面的代碼可以放心寫個循環,且遞歸後不必跳出,因為當返回該點時,該點所連的其他邊必然已經被走過了。因此答案裏存的就是一條完整的路徑。

無序字母對:https://www.luogu.org/problemnew/show/P1341


這道題的話,還是浪費了很多時間,一是因為歐拉回路以前沒寫過,而是因為這道題答案保存那裏有點玄學問題,默默改成棧就過了。字符的處理也需要註意一下。

技術分享圖片
 1 #include<cstdio>
 2 #include<stack>
 3 using namespace std;
 4 const int maxn=55;
 5 int n,G[maxn][maxn],d[maxn];
 6 stack<int> ans; //用棧倒序保存答案
 7 int toInt(char c) { //字符轉為整數
 8     if(c>=A&&c<=Z) return c-A+1;
 9     return c-a+27;
10 }
11 char toChar(int i) { //整數轉為字符
12     if(i>=1&&i<=26) return i-1+A;
13     return i-27+a;
14 }
15 void euler(int u) {
16     for(int v=1;v<=52;++v)
17         if(G[u][v]) {
18             G[u][v]=G[v][u]=0; //刪邊
19             euler(v);
20         }
21     ans.push(u);
22 }
23 int main() {
24     scanf("%d",&n);
25     char cu,cv;
26     int u,v;
27     for(int i=1;i<=n;++i) {
28         while((cu=getchar())==\n||cu== ||cu==\r); //過濾無用字符
29         cv=getchar();
30         u=toInt(cu),v=toInt(cv);
31         G[u][v]=G[v][u]=1;
32         ++d[u],++d[v]; //統計度數
33     }
34     int s=0,cnt=0;
35     for(int i=1;i<=52;++i) //找起點和判斷是否存在歐拉道路
36         if(d[i]&1) {
37             ++cnt;
38             if(!s) s=i;
39         }
40     if(!cnt) for(int i=1;i<=52;++i)
41         if(d[i]) {
42             s=i;
43             break;
44         }
45     if(cnt&&cnt!=2) {
46         printf("No Solution\n");
47         return 0;
48     }
49     euler(s);
50     if((int)ans.size()<n+1) printf("No Solution");
51     while(!ans.empty()) {
52         int p=ans.top();
53         ans.pop();
54         printf("%c",toChar(p));
55     }
56     putchar(\n);
57     return 0;
58 }
AC代碼

歐拉回路&【洛谷習題】無序字母對