SGU101 求有重边的无向图欧拉迹
生活随笔
收集整理的這篇文章主要介紹了
SGU101 求有重边的无向图欧拉迹
小編覺得挺不錯的,現在分享給大家,幫大家做個參考.
題意:好多木棒,倆端有數字(0--6)標記,按數字相同的端首尾相連成一條直線(木棒可以相同)。即求有重邊的無向圖歐拉跡。
而回溯的時候記錄,原因較復雜,大致證明如下:
分幾種情況討論即可:
1,只有偶數結點。任選一個點,必然從一條出發回到該點,直到無邊為止,回溯時邊自然連續。
#include<iostream> #include<cstdio> #include<cstring> using namespace std; int n;int nume=0; int e[205][2];int head[10]; void adde(int f,int l) {e[nume][0]=l;e[nume][1]=head[f];head[f]=nume++;e[nume][0]=f;e[nume][1]=head[l];head[l]=nume++; } int degree[8]; //度數 int vis[205]; //標記訪問 void dfs1(int u) //判斷連通 { for(int i=head[u];i!=-1;i=e[i][1]){int v=e[i][0];if(!vis[v]){vis[v]=1;dfs1(v);}} } int ans[205][2];int ansnum=0; void dfs2(int u) //求歐拉跡 {for(int i=head[u];i!=-1;i=e[i][1]){if(!vis[i]){vis[i]=1; //此處同時標記雙向邊!!!。vis[i^1]=1;int v=e[i][0];dfs2(v); //回溯的時候記錄邊,恰是一條歐拉路。if(i%2==0)ans[ansnum++][0]=i/2+1;elseans[ansnum++][1]=i/2+1;}} } int main() {scanf("%d",&n);for(int i=0;i<8;i++)head[i]=-1;int tf,tl;int tbegin=0;for(int i=0;i<n;i++) {scanf("%d%d",&tf,&tl);tbegin=tf;degree[tf]++;degree[tl]++;adde(tf,tl);}int count=0;int jis=0;;for(int i=0;i<=6;i++) //度數判定{if(degree[i]%2){count++;jis=i;}}if(count==0||count==2){int mark=1;vis[tbegin]=1;dfs1(tbegin); for(int i=0;i<=6;i++) //連通性判定if(vis[i]==0&°ree[i]>0)mark=0;if(mark==0){ printf("No solution\n");return 0;}for(int i=0;i<205;i++)vis[i]=0;if(count==0) dfs2(tbegin);elsedfs2(jis);for(int i=ansnum-1;i>=0;i--) //逆序輸出{if(ans[i][0]!=0)printf("%d +\n",ans[i][0]);elseprintf("%d -\n",ans[i][1]);}}elseprintf("No solution\n");}
先判定是否為歐拉圖,倆個條件,不說了。如果是歐拉圖,輸出路經。
方法:dfs遍歷邊,回溯時候記錄邊,遍歷過了就標記“雙向邊”.
那么所記錄的恰好是一條逆歐拉跡。不可以前進的時候標記,原因:有可能一筆畫失敗,導致邊不連續,而回溯的時候記錄,原因較復雜,大致證明如下:
分幾種情況討論即可:
1,只有偶數結點。任選一個點,必然從一條出發回到該點,直到無邊為止,回溯時邊自然連續。
2,有2個奇數結點。當回到某個點時無論圈有沒走,必然也連續,見圖:
#include<iostream> #include<cstdio> #include<cstring> using namespace std; int n;int nume=0; int e[205][2];int head[10]; void adde(int f,int l) {e[nume][0]=l;e[nume][1]=head[f];head[f]=nume++;e[nume][0]=f;e[nume][1]=head[l];head[l]=nume++; } int degree[8]; //度數 int vis[205]; //標記訪問 void dfs1(int u) //判斷連通 { for(int i=head[u];i!=-1;i=e[i][1]){int v=e[i][0];if(!vis[v]){vis[v]=1;dfs1(v);}} } int ans[205][2];int ansnum=0; void dfs2(int u) //求歐拉跡 {for(int i=head[u];i!=-1;i=e[i][1]){if(!vis[i]){vis[i]=1; //此處同時標記雙向邊!!!。vis[i^1]=1;int v=e[i][0];dfs2(v); //回溯的時候記錄邊,恰是一條歐拉路。if(i%2==0)ans[ansnum++][0]=i/2+1;elseans[ansnum++][1]=i/2+1;}} } int main() {scanf("%d",&n);for(int i=0;i<8;i++)head[i]=-1;int tf,tl;int tbegin=0;for(int i=0;i<n;i++) {scanf("%d%d",&tf,&tl);tbegin=tf;degree[tf]++;degree[tl]++;adde(tf,tl);}int count=0;int jis=0;;for(int i=0;i<=6;i++) //度數判定{if(degree[i]%2){count++;jis=i;}}if(count==0||count==2){int mark=1;vis[tbegin]=1;dfs1(tbegin); for(int i=0;i<=6;i++) //連通性判定if(vis[i]==0&°ree[i]>0)mark=0;if(mark==0){ printf("No solution\n");return 0;}for(int i=0;i<205;i++)vis[i]=0;if(count==0) dfs2(tbegin);elsedfs2(jis);for(int i=ansnum-1;i>=0;i--) //逆序輸出{if(ans[i][0]!=0)printf("%d +\n",ans[i][0]);elseprintf("%d -\n",ans[i][1]);}}elseprintf("No solution\n");}
轉載于:https://www.cnblogs.com/yezekun/p/3925729.html
總結
以上是生活随笔為你收集整理的SGU101 求有重边的无向图欧拉迹的全部內容,希望文章能夠幫你解決所遇到的問題。