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

歡迎訪問 生活随笔!

生活随笔

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

编程问答

重新安排行程

發(fā)布時間:2024/4/18 编程问答 35 豆豆
生活随笔 收集整理的這篇文章主要介紹了 重新安排行程 小編覺得挺不錯的,現(xiàn)在分享給大家,幫大家做個參考.

思路

直覺上來看 這道題和回溯法沒有什么關(guān)系,更像是圖論中的深度優(yōu)先搜索。
實際上確實是深搜,但這是深搜中使用了回溯的例子,在查找路徑的時候,如果不回溯,怎么能查到目標路徑呢。

所以可以說本題也是回溯法。

「這道題目有幾個難點:」

1、一個行程中,如果航班處理不好容易變成一個圈,成為死循環(huán)
2、有多種解法,字母序靠前排在前面,該如何記錄映射關(guān)系呢
3、使用回溯法(也可以說深搜) 的話,那么終止條件是什么呢?
4、搜索的過程中,如何遍歷一個機場所對應(yīng)的所有機場。

如何理解死循環(huán)


這個例子就是說,出發(fā)機場和到達機場也會重復(fù)的,「如果在解題的過程中沒有對集合元素處理好,就會死循環(huán)。」

如何記錄映射關(guān)系

題目提示說:
如果存在多種有效的行程,請你按字符自然排序返回最小的行程組合。
例如,行程 [“JFK”, “LGA”] 與 [“JFK”, “LGB”] 相比就更小,排序更靠前。

所以一個機場映射多個機場,多個機場之間要靠字母序排列

一個機場映射機一個機場,可以使用std::unordered_map<X,Y>。

如果讓一個機場映射多個機場的話std::unordered_map<X,xY>,多個機場之間再有順序的話,就是用std::map 或者std::multimap 或者 std::multiset。

這樣存放映射關(guān)系可以定義為 unordered_map<string, multiset> targets 或者 unordered_map<string, map<string, int>> targets。

含義如下:

unordered_map<string, multiset> targets:unordered_map<出發(fā)機場, 到達機場的集合> targets

unordered_map<string, map<string, int>> targets:unordered_map<出發(fā)機場, map<到達機場, 航班次數(shù)>> targets

這兩個結(jié)構(gòu),后者優(yōu)于前者,因為如果使用unordered_map<string, multiset> targets 遍歷multiset的時候,不能刪除元素,一旦刪除元素,迭代器就失效了。

「再說一下為什么一定要增刪元素呢,正如開篇給出的圖中所示,出發(fā)機場和到達機場是會重復(fù)的,搜索的過程沒及時刪除目的機場就會死循環(huán)。」

所以搜索的過程中就是要不斷的刪multiset里的元素,那么推薦使用unordered_map<string, map<string, int>> targets。

在遍歷 unordered_map<出發(fā)機場, map<到達機場, 航班次數(shù)>> targets的過程中,「可以使用"航班次數(shù)"這個字段的數(shù)字做相應(yīng)的增減,來標記到達機場是否使用過了。」

如果“航班次數(shù)”大于零,說明目的地還可以飛,如果如果“航班次數(shù)”等于零說明目的地不能飛了,而不用對集合做刪除元素或者增加元素的操作。

「相當于說我不刪,我就做一個標記!」

回溯三部曲

1、遞歸函數(shù)參數(shù)

使用unordered_map<string, map<string, int>> targets; 來記錄航班的映射關(guān)系
還需要ticketNum,表示有多少個航班(終止條件會用上)。

// unordered_map<出發(fā)機場, map<到達機場, 航班次數(shù)>> targets unordered_map<string, map<string, int>> targets; bool backtracking(int ticketNum, vector<string>& result) {

返回值是bool是因為我們只需要找到一個行程,就是在樹形結(jié)構(gòu)中唯一的一條通向葉子節(jié)點的路線。

當然本題的targets和result都需要初始化,代碼如下:

for (const vector<string>& vec : tickets) {targets[vec[0]][vec[1]]++; // 記錄映射關(guān)系 } result.push_back("JFK"); // 起始機場

tickets->[[“JFK”, “KUL”], [“JFK”, “NRT”], [“NRT”, “JFK”]

2、遞歸終止條件

拿題目中的示例為例,輸入: [[“MUC”, “LHR”], [“JFK”, “MUC”], [“SFO”, “SJC”], [“LHR”, “SFO”]] ,這是有4個航班,那么只要找出一種行程,行程里的機場個數(shù)是5就可以了。

所以終止條件是:我們回溯遍歷的過程中,遇到的機場個數(shù),如果達到了(航班數(shù)量+1),那么我們就找到了一個行程,把所有航班串在一起了。

if (result.size() == ticketNum + 1) {return true; }

不需要收集結(jié)果,本題的result相當于 回溯算法:求組合總和!中的path,也就是本題的result就是記錄路徑的(就一條),在如下單層搜索的邏輯中result就添加元素了。

3、單層搜索的邏輯
回溯的過程中,如何遍歷一個機場所對應(yīng)的所有機場呢?

「可以說本題既要找到一個對數(shù)據(jù)進行排序的容器,而且還要容易增刪元素,迭代器還不能失效」。

所以選擇了unordered_map<string, map<string, int>> targets 來做機場之間的映射。

for (pair<const string, int>& target : targets[result[result.size() - 1]]) {if (target.second > 0 ) { // 記錄到達機場是否飛過了result.push_back(target.first);target.second--;if (backtracking(ticketNum, result)) return true;result.pop_back();target.second++;}}

可以看出 通過unordered_map<string, map<string, int>> targets里的int字段來判斷 這個集合里的機場是否使用過,這樣避免了直接去刪元素。

class Solution { public:// unordered_map<出發(fā)機場, map<到達機場, 航班次數(shù)>> targetsunordered_map<string,map<string,int>> targets;vector<string> res;//收集結(jié)果bool backtracking(vector<vector<string>>& tickets){if(res.size()==tickets.size()+1){return true;}for(pair<const string,int>& target:targets[res[res.size()-1]]){if(target.second>0){// 記錄到達機場是否飛過了res.push_back(target.first);target.second--;if(backtracking(tickets)) return true;res.pop_back();target.second++;}}return false;}vector<string> findItinerary(vector<vector<string>>& tickets) {for(const vector<string>& vec:tickets){targets[vec[0]][vec[1]]++;// 記錄映射關(guān)系}res.push_back("JFK");backtracking(tickets);return res;} };

總結(jié)

以上是生活随笔為你收集整理的重新安排行程的全部內(nèi)容,希望文章能夠幫你解決所遇到的問題。

如果覺得生活随笔網(wǎng)站內(nèi)容還不錯,歡迎將生活随笔推薦給好友。