332. 重新安排行程(图,dfs(深度优先搜索))

 原文链接:https://leetcode-cn.com/problems/reconstruct-itinerary/solution/332-zhong-xin-an-pai-xing-cheng-hui-su-fa-shen-sou/

题目描述:

给你一份航线列表 tickets ,其中 tickets[i] = [fromi, toi] 表示飞机出发和降落的机场地点。请你对该行程进行重新规划排序。

所有这些机票都属于一个从 JFK(肯尼迪国际机场)出发的先生,所以该行程必须从 JFK 开始。如果存在多种有效的行程,请你按字典排序返回最小的行程组合。

  • 例如,行程 ["JFK", "LGA"] 与 ["JFK", "LGB"] 相比就更小,排序更靠前。

假定所有机票至少存在一种合理的行程。且所有的机票 必须都用一次 且 只能用一次。

输入:tickets = [["MUC","LHR"],["JFK","MUC"],["SFO","SJC"],["LHR","SFO"]]
输出:["JFK","MUC","LHR","SFO","SJC"]

输入:tickets = [["JFK","SFO"],["JFK","ATL"],["SFO","ATL"],["ATL","JFK"],["ATL","SFO"]]
输出:["JFK","ATL","JFK","SFO","ATL","SFO"]
解释:另一种有效的行程是 ["JFK","SFO","ATL","JFK","ATL","SFO"] ,但是它字典排序更大更靠后。 

 算法思路:

代码随想录:一个非常好的学数据结构和算法的微信公众号

递归模板:

backtracking() {
    if (终止条件) {
        存放结果;
    }

    for (枚举同一个位置的所有可能性,可以想成节点孩子的数量) {
        递归,处理节点;
        backtracking();
        回溯,撤销处理结果
    }
}

  • 首先如何存储图的结构,选择unordered_map<string,map<string,int>>进行存储,因为需要返回字典序最小的路径,因此后方选择map进行存储《开始城市,《到达城市,航班数》》这里利用航班数的自加和自减,进行城市之间是否连通。
  • 其他详细内容见代码注释。


代码实现:

class Solution {
private:
    unordered_map<string,map<string,int>> target;
    //使用unordered_map存储图的结构,因为路线中可能存在环路,所以进行递归时,要及时对城市进行处理,又因为结果要按照字典序排序,返回最小字典序的答案,因此选择map实现。《出发城市,<到达城市,航班数>》,这里使用航班数来进行伪装的删除和添加操作。
    bool track(int ticketsNum,vector<string>& result){
    //递归的结束条件是什么呢?行程里的元素个数=票数+1,这个就是递归结束的条件
        if(result.size()==ticketsNum+1){
            return true;
        }
    //遍历存储好的图的结构:
    //target[result[result.size()-1]],result中存的是string,target的类型是unordered_map<string,map<string,int>>,result的类型是vector<string>,则vec的类型为map<string,int>类型
    //result[result.size()-1]在最初的状态时result中只有JFK,则result[1-1]为JFK,遍历与JFK相连的城市
        for(auto &vec:target[result[result.size()-1]]){
            if(vec.second>0){//如果航班数大于0,说明存在机票,
                result.push_back(vec.first);//将到达的城市push到result
                vec.second--;//航班数-1
                if(track(ticketsNum,result)){//递归
                    return true;
                }
                result.pop_back();//回溯恢复原来的状态,将压入的值pop出,航班数+1
                vec.second++;
            }
        }
        return false;//没有返回true的情况下,返回false
    }
public:
    vector<string> findItinerary(vector<vector<string>>& tickets) {
        vector<string> result;//存放最终的路线
        for(auto& vec:tickets){//记录映射关系
            target[vec[0]][vec[1]]++;// target[vec[0]]此时指的为《string,int》,后面跟[vec[1]]指向int航班数,++,表示存在航班数,记录映射关系,可以将其看做n维数组。
        }
        result.push_back("JFK");//将开始城市压入result中
        track(tickets.size(),result);//递归
        return result;
    }
};

对我而言,一些复杂的数据类型,使我脑袋迟缓。

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值