日韩性视频-久久久蜜桃-www中文字幕-在线中文字幕av-亚洲欧美一区二区三区四区-撸久久-香蕉视频一区-久久无码精品丰满人妻-国产高潮av-激情福利社-日韩av网址大全-国产精品久久999-日本五十路在线-性欧美在线-久久99精品波多结衣一区-男女午夜免费视频-黑人极品ⅴideos精品欧美棵-人人妻人人澡人人爽精品欧美一区-日韩一区在线看-欧美a级在线免费观看

歡迎訪問 生活随笔!

生活随笔

當前位置: 首頁 > 编程资源 > 编程问答 >内容正文

编程问答

csp 201512-4 送货(hierholzer算法的递归和堆栈实现)

發布時間:2023/12/10 编程问答 45 豆豆
生活随笔 收集整理的這篇文章主要介紹了 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算法的递归和堆栈实现)的全部內容,希望文章能夠幫你解決所遇到的問題。

如果覺得生活随笔網站內容還不錯,歡迎將生活随笔推薦給好友。