csp 201512-4 送货(hierholzer算法的递归和堆栈实现)
原題【傳送門】
該題為求解歐拉路的問題。
一、背景知識
歐拉路:給定無孤立節點的圖G,若存在一條路,經過圖中每一邊一次且僅一次,則該路稱為歐拉路。
歐拉回路:若存在一條回路,經過圖中的每一邊一次且僅一次,則該回路稱為歐拉回路。
歐拉圖:具有歐拉回路的圖稱為歐拉圖。
判定定理:無向圖G具有一條歐拉路,當且僅當G是連通的,且有0個或2個奇數度結點。
--------以上來自左孝凌的《離散數學》
二、題目分析
給定一個圖,存在歐拉路,則依次輸出其經過結點;如果存在多條,則輸出字典序最小的;如果不存在,則輸出-1;
由于歐拉回路是一種特殊的歐拉路,所以判定定理仍然有效。題目中沒有特殊要求是回路,則都按照歐拉路處理即可。
由判定定理,需要先判斷:是連通圖且只有0或2個奇數度結點。判斷連通圖可用并查集實現。
接著采用Hierholzer 算法求出歐拉路。
三、Hierholzer 算法
遞歸思路:
1.判斷奇點數。奇點數若為0則任意指定起點,奇點數若為2則指定起點為奇點。
2.開始遞歸函數Hierholzer(x):
循環尋找與x相連的邊(x,u):
刪除(x,u)
刪除(u,x)
Hierholzer(u);
將x插入答案隊列之中
3.倒序輸出答案隊列。
堆棧思路:
1.判斷奇點數。奇點數若為0則任意指定起點,奇點數若為2則指定起點為奇點,將起點入棧。
2. 若棧不為空:
取棧頂元素 x(區別彈棧)
x 連接的邊數為0:
將該元素加入答案隊列
彈棧
x 連接的邊數不為0:
尋找與其相連的邊 (x,u)
刪除(x,u)
刪除(u,x)
u入棧
3.倒序輸出答案隊列。
四、代碼
#include<stdio.h> #include<vector> #include<set> using namespace std; int n,m; const int maxn=10001; set<int> edges[maxn];//set自然成升序,每次取出第一個即可。 vector<int> ans; int father[maxn]; int find_father(int s){//尋找祖宗int a=s;while(father[a]!=a){//找到祖宗為:aa=father[a];}while(s!=a){//回溯,減小高度進而減小時間復雜度int tmp=s;s=father[s];father[tmp]=a;}return a; } bool test(){//檢測是否存在歐拉路int fnum=0;for(int i=1;i<=n;i++){//數連通子圖的個數if(father[i]==i) fnum++;}if(fnum>1) return 0; //非聯通圖int num=0;for(int i=1;i<=n;i++){//奇數節點個數if(edges[i].size() %2==1){ //更好的寫法:if(edges[i].size()&1){...}num++;}}if(num==2) {//如果是2個奇數節點,檢測1是否為奇數度。if(edges[1].size()%2==1) return 1; //或者:return edges[1].size()%2else return 0;}else if(num==0) return 1;else return 0; } void dfs(int s){//遞歸寫法,只有80分,爆棧while(!edges[s].empty()){int v=*edges[s].begin() ;edges[s].erase(v);edges[v].erase(s); dfs(v); }ans.push_back(s); return; } void dfs1(int s){//棧寫法,滿分path.push_back(s);while(!path.empty() ){int cur=path.back() ;if(edges[cur].empty()){ans.push_back(cur);path.pop_back() ; }else{int v=*edges[cur].begin() ;edges[cur].erase(v);edges[v].erase(cur);path.push_back(v); }} } int main(){scanf("%d%d",&n,&m);int u,v;for(int i=1;i<=n;i++){father[i]=i;}for(int i=0;i<m;i++){scanf("%d%d",&u,&v);int uf=find_father(u);int vf=find_father(v);if(uf!=vf) father[vf]=uf;//新讀入的邊將兩個連通子圖連通edges[u].insert(v);edges[v].insert(u); }if(!test()){printf("-1"); return 0;}dfs1(1);for(int i=ans.size() -1 ;i>=0;i--){//倒序輸出printf("%d ",ans[i]);}return 0; }五、參考與感想
歐拉回路求解算法
CCF CSP 競賽試題——送貨(201512-4)(真的100分)
第二個參考的代碼真的厲害,可惜有些沒看懂。
大家都看到這里了,點個贊吧,嘿嘿~
總結
以上是生活随笔為你收集整理的csp 201512-4 送货(hierholzer算法的递归和堆栈实现)的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: 如何改变XCode的默认设置
- 下一篇: Linux基础-目录与路径