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

歡迎訪問 生活随笔!

生活随笔

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

编程问答

IDDFS学习笔记-埃及分数

發布時間:2024/3/24 编程问答 49 豆豆
生活随笔 收集整理的這篇文章主要介紹了 IDDFS学习笔记-埃及分数 小編覺得挺不錯的,現在分享給大家,幫大家做個參考.

? ? ? ? 迭代加深搜索算法(iterative deepening depth-first search (IDS or IDDFS)) 可以被視作是廣度優先搜索算法(BFS)和深度優先搜索算法(DFS)的結合。常用于解決在廣度很深度上都無限的問題,最經典的便是埃及分數:


在古埃及,人們使用單位分數的和(形如1/a的, a是自然數)表示一切有理數。如:2/3=1/2+1/6,但不允許2/3=1/3+1/3,
因為加數中有相同的。對于一個分數a/b,表示方法有很多種,但是哪種最好呢?首先,加數少的比加數多的好,其次,加數
個數相同的,最小的分數越大越好。
如:19/45=1/3 + 1/12 + 1/180
19/45=1/3 + 1/15 + 1/45
19/45=1/3 + 1/18 + 1/30,
19/45=1/4 + 1/6 + 1/180
19/45=1/5 + 1/6 + 1/18.
最好的是最后一種,因為1/18比1/180,1/45,1/30,1/180都大。
給出a,b( 0 < a < b < 1000),編程計算最好的表達方式。
Input:
a b
Output:
一個等式

Sample Input:
3 4
Sample Output:
3/4 = 1/2 + 1/4? ??


? ? ? ? 埃及分數問題的廣度(單位分數的大小)和深度(單位分數的求和數量)都是無限的。在單純的DFS問題中,很多時候剪枝技術只是一種優化,但在IDDFS中,剪枝直接限定了合理有效的邊界,使搜索在有限的范圍內進行,使得回溯和搜索都成為了可能。因此在IDDFS中,如何剪枝成為了不可繞過的重要話題,直接決定了是否能合理地解決問題。

? ? ? ? 簡要回顧以下IDDFS的思想:逐漸增加DFS的遞歸深度,同時每一層都采用BFS進行搜索,可以說IDDFS就是用DFS串起來的BFS,又或者用筆者在DFS筆記中的類比,DFS是”動態循環“,普通的DFS的循環體只是一個簡單判斷,而IDDFS中的循環體就是一個BFS。

? ? ? ? 本題存在兩個維度的最優解情況:1、和式中的分數最少,2、和式中的最小的分數最大(分母最小),其中2是在1的條件下進行判斷。考慮到IDDFS中DFS和BFS的從屬關系,自然1應當由DFS處理,而2則是BFS。

? ? ? ? 接下來具體分析一下題目,首先本題采用分數作為結果,為了保證過程沒有誤差,采用浮點型進行計算是錯誤且復雜的,會牽扯到小數和分數的轉換問題。在本題中,對于分數而言分子和分母成對出現,不如用pair<int,int>來儲存它們,first是分子,second是分母。在此基礎上,需要重新定義這種特殊類型的分數的求和函數:

int gcd(int a,int b) //輾轉相除法求公約數 {return b==0 ? a : gcd(b,a%b);} pair<int,int> sum(pair<int,int> a, pair<int,int> b){pair<int,int> result;int c = a.first*b.second+b.first*a.second;int d = a.second*b.second;int g = abs(gcd(d,c));c /= g; d /= g;result.first = c; result.second = d;return result; }

? ? ? ? 有了求和方法之后似乎分數運算變得可行,如果要比大小的話只需要將其中一個的first*(-1)傳入,再比較結果的符號即可。同時本題需要輸出一個和式,這個和式再DFS的過程中也需要被跟蹤,所以不妨先放出兩個字符串和整型互轉函數:

string ItS(int num){string str;stringstream ss;ss<<num;ss>>str;return str; } int StI(string str){int num;stringstream ss;ss<<str;ss>>num;return num; }

? ? ? ? 準備好基本工具后我們來理一下解題思路:先試2個分數的和,再試3個分數的和,再...直到在第n個分數的和找到了我們想要的結果a/b,便解決了最優解條件1,再在這一層中繼續尋找別的可能解且不再深入,最后根據最優解條件2排序,輸出最優解。

? ? ? ? 從深度上說,IDDFS中DFS的部分往往需要兩個基本參數(now和deep),now是當前的遞歸深度,deep是最深的遞歸深度,一旦now=deep則返回,deep+1后再繼續,deep則有主函數給出。所以IDDFS的遞歸思路是從0-1,再0-2,再0-3...直到解決問題。

? ? ? ? 埃及分數是恒有解問題,這一點在題目中也有暗示(沒有impossible的情況),且大部分IDDFS的問題在深度上的無限正體現在這一點上。因此我們不用擔心由于深度無限而無法跳出,我們總會找到合適的解,并且事實上它不會在深度上花費太多。

? ? ? ? 而在廣度上,我們需要不斷地求和,并記錄這些和的結果,運用到下一層的BFS中去,為了簡單說明這個問題的思路,我們將算法中位于+號左邊的稱為“頭”,位于+號右邊的稱為“尾”,作為暴力算法,遍歷求和的思路便是將頭作為外循環,尾作為內循環,儲存求和結果,下面用一個代碼解釋這個思路:

for(int head=0;head<10;head++){for(int tail = head+1;tail<10;tail++){int sum = head + tail;} }

? ? ? ? 在IDDFS中,這個head來自于上一層的BFS中,而這個tail正是當前層的BFS給出的遍歷,而sum則是當前層BFS的搜索用元。DFS則在其中擔任傳遞head的作用,并且決定傳遞幾層。

? ? ? ? 了解了BFS和DFS再IDDFS中分別擔任的角色和它們互相作用的原理關系,接下來我們需要解決能使整個解決過程變得可行,變得不再無窮的核心問題——如何剪枝。

? ? ? ? 事實上在這里稱剪枝或許并不準確,畢竟剪枝是DFS中用于避免無效遞歸的手段,而在IDDFS中,實際上我們更關注給BFS進行“劃界”,使得BFS在一個合理的范圍內搜索,剩余的無窮的無效范圍是不必要的。

? ? ? ? 在本題中的“劃界”方法是:用遞增順序枚舉分數,如果接下來的遞歸層數(deep-now)全加上目前這個分數(1/n)仍然小于目標值(a/b),說明剩下的分數枚舉是無效的,可以直接結束枚舉,劃出右界,同時如果當前分數比目標分數大,則同樣不需要枚舉,劃出左界。給出檢測函數:

int check(pair<int,int>now, int after, int deep){//after是小于當前枚舉分數的最大分數的分母,pair<int,int> p; //deep為遞歸深度,同時也是求和寬度 pair<int,int>temp;p.first = deep; p.second = after;temp.first = a*(-1); temp.second = b;if(sum(now,temp).first>0) return 2; //左界以左p = sum(now,p);p = sum(p,temp);return(p.first>=0); //右界以右 }

? ? ? ? 之所以check函數不用bool型而是用int型,是因為需要區分左界以左,右界以右和在范圍內三種情況,在住主函數中需要另外處理它們,保證主函數給出的head是左界,使IDDFS效率更高。

? ? ? ? 有了IDDFS的基礎模塊check劃界后,我們繼續解決題目中的具體問題。

? ? ? ? 首先是記錄每個head的加合路徑,這個路徑將再最后被調用輸出,簡單寫一個字符串函數,同時用map<pair<int,int>,stirng>來儲存它們:

string road(string pre, pair<int,int> next){string str;str = pre + " + " + ItS(next.first) + "/" + ItS(next.second);return str; }

? ? ? ? 另外,在BFS中tail的左值取決于head的road中的最后一個分數,并且如果最后目標值有多解,我們還需要比較它們最后一個分數的大小,所以需要一個提取最后一個分數分母的函數:

int GetStringTail(string str){ //找到分數加和式中的最后一個分母 int num;string st;for(string::reverse_iterator it=str.rbegin();it!=str.rend();it++){if((*it)=='/') break; st+=(*it); }reverse(st.begin(),st.end());stringstream ss;ss<<st;ss>>num;return num; }

? ? ? ? ? 最后還有一些細節:在讀入目標分數后,首先進行化簡,不然分母是錯誤的。如果目標分數的分子是1(已經是埃及分數),避免麻煩,直接輸出即可。

? ? ? ? 整合它們!

#include<bits/stdc++.h> using namespace std; int a, b; bool findthedeep; map<pair<int,int>,string> m; vector<string> result; int gcd(int a,int b) //輾轉相除法求公約數 { return b==0 ? a : gcd(b,a%b);} pair<int,int> sum(pair<int,int> a, pair<int,int> b){pair<int,int> result;int c = a.first*b.second+b.first*a.second;int d = a.second*b.second;int g = abs(gcd(d,c));c /= g; d /= g;result.first = c; result.second = d;return result; } string ItS(int num){string str;stringstream ss;ss<<num;ss>>str;return str; } int StI(string str){int num;stringstream ss;ss<<str;ss>>num;return num; } int check(pair<int,int>now, int after, int deep){ //after是小于當前枚舉分數的最大分數的分母,pair<int,int> p; //deep為遞歸深度,同時也是求和寬度 pair<int,int>temp;p.first = deep; p.second = after;temp.first = a*(-1); temp.second = b;if(sum(now,temp).first>0) return 2;p = sum(now,p);p = sum(p,temp);return(p.first>=0); } string road(string pre, pair<int,int> next){string str;str = pre + " + " + ItS(next.first) + "/" + ItS(next.second);return str; } int GetStringTail(string str){ //找到分數加和式中的最后一個分母 int num;string st;for(string::reverse_iterator it=str.rbegin();it!=str.rend();it++){if((*it)=='/') break; st+=(*it); }reverse(st.begin(),st.end());stringstream ss;ss<<st;ss>>num;return num; } void IDDFS(pair<int,int> top, int now, int deep){ if(now == deep) return;queue<pair<int,int>> q; int k = 0; int s = GetStringTail(m[top]);for(int i=s+1;;i++){if(check(top,i,deep-now) != 1) break;pair<int,int> num;num.first = 1; num.second = i;q.push(num);k++;}pair<int,int> head, next;while(k--){head = q.front();q.pop();next = sum(top,head);q.push(next);m[next] = road(m[top],head);if(next.first == a && next.second == b){result.push_back(m[next]);findthedeep = 1;}}while(!q.empty()){IDDFS(q.front(),now+1,deep);q.pop();}return; } int main(){cin>>a>>b;cout<<a<<"/"<<b<<"=";int c = gcd(a,b);a /= c; b /= c; //化簡 if(a==1){cout<<a<<"/"<<b;return 0;}queue<pair<int,int>> q;pair<int,int> top;for(int i=2;;i++){for(int t=2;;t++){top.first = 1; top.second = t;if(check(top,top.second+1,i) == 0) break;if(check(top,top.second+1,i) == 2) continue;q.push(top);}while(!q.empty()){m.clear();top = q.front();q.pop();m[top] = "1/" + ItS(top.second); IDDFS(top,1,i); }if(findthedeep) break;}int max = 0;string res;for(int i=0;i<result.size();i++){int num = GetStringTail(result[i]);if(max>num || max==0){max = num;res = result[i];}}cout<<res<<endl;return 0; }

? ? ? ? 最后的補充:在IDDFS中,實際上是對DFS和BFS的配合使用,主要分為以下3個要點:

? ? ? ? 1、BFS:依然是找到核心隊列,注意結合DFS的遞歸深度劃分左右界。

? ? ? ? 2、DFS:依然是找到核心遞歸,注意逐步加深遞歸深度。

? ? ? ? 3、DFS給BFS傳遞枚舉head,BFS負責找到最優解。

? ? ? ? 4、IDDFS的核心是變化深度上限的DFS,BFS很多時候是被忽視甚至是可以代替的。

? ? ? ? 5、IDDFS要注意逐漸加深的深度的數據意義,能夠幫助快速架構算法邏輯。

總結

以上是生活随笔為你收集整理的IDDFS学习笔记-埃及分数的全部內容,希望文章能夠幫你解決所遇到的問題。

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

主站蜘蛛池模板: 亚洲色图欧美色 | 日韩欧美亚洲天堂 | 天天干夜夜夜 | 国产又黄又粗又猛又爽视频 | 日本在线观看视频网站 | 亚洲欧美国产高清 | 一级做a爱片久久毛片 | 视色视频在线观看 | 午夜国产一区 | 免费九九视频 | 深夜网站在线 | 综合精品在线 | 一区二区三区视频在线观看 | 国产人妻精品午夜福利免费 | 免费观看成人 | 超碰免费公开在线 | 国产成人啪精品 | 色综合色综合网色综合 | av免费亚洲 | www.youjizz国产 | 久久国产精品亚洲 | 亚洲国产精品综合久久久 | 午夜草草 | 免费一区二区在线观看 | 久视频在线 | 麻豆国产精品777777在线 | ass日本粉嫩pics珍品 | 成人动漫一区二区 | 极品销魂美女少妇尤物 | 亚洲一区二区三区四区五区xx | 黄色字幕网 | 日韩av三级在线 | 人人爽视频| ass亚洲熟妇毛耸耸pics | 第一福利在线视频 | av天天草 | 午夜免费福利视频 | 欧美又粗又深又猛又爽啪啪九色 | 美女又爽又黄视频毛茸茸 | 欧美一区二 | 精品无码国产污污污免费网站 | 日韩 国产| 黄色一级免费网站 | 日韩有色| 91私密视频| 亚洲AV成人无码久久精品同性 | 成人av在线网 | 人人爽人人爽人人爽人人爽 | 国产精品无码电影在线观看 | 中国爆后菊女人的视频 | 天天综合天天做天天综合 | 国产69精品久久久久久久久久 | 五月激情丁香网 | 欧洲中文字幕日韩精品成人 | 日本高清无吗 | 欧美视频在线观看一区 | 亚洲视频一二三 | 久久亚洲精品国产 | 天天操天天弄 | 欧美一区二区成人 | 尤物一区 | 精品91自产拍在线观看二区 | 91麻豆产精品久久久久久 | 黄色二级视频 | 女同性αv亚洲女同志 | 青青草原免费观看 | 亚洲系列在线观看 | 高h捆绑拘束调教小说 | 久久激情婷婷 | 亚洲午夜精品 | 日本五十肥熟交尾 | 大牛影视剧免费播放在线 | 木下凛凛子av一区二区三区 | 日本免费网站在线观看 | 欧美一二三 | 亚洲欧洲综合 | 欧美伦理一区 | 久久精品无码一区二区三区免费 | 国产乱淫视频 | 日本爽爽爽爽爽爽在线观看免 | 快播91| 日本不卡二区 | 亚洲一区二区三区四区五区午夜 | 中日韩在线观看视频 | 色播视频在线播放 | 日韩女同互慰一区二区 | 久久久久极品 | 欧美7777 | 国产素人在线观看 | 黑人大群体交免费视频 | 免费观看黄色小视频 | 色屁屁www影院免费观看入口 | 中文字幕码精品视频网站 | 亚洲一区二区福利视频 | 丰满人妻一区二区三区免费 | 亚洲女同一区二区 | 毛片毛片毛片毛片毛片毛片毛片毛片 | 国产色自拍 | 天天曰夜夜操 |