欧拉路径 Hierholzer 算法

这篇博客介绍了如何运用回溯法和Hierholzer算法解决旅行路线规划问题。通过排序机票、建立图并进行深度优先搜索,确保一笔画路径的正确性。两种方法分别在不同策略下找到从起点到终点的有效路径,最终得到满足字典序的行程列表。
摘要由CSDN通过智能技术生成

思路

普通节点出度和入度数是相等的,在while用完之前,我有入有出,又回去了,但是最后一个节点就不一样了,其出度数必定比入度数小1,最后一次走到这,应该是入度1次,出度0次,进来了发现回不去了呀,输出了我们的第一个需要的节点,也就是终点,同理,开始节点出度比入度大1,最后别人都走完了,他还要出最后一次,出完这一次,才能输出,也就是保证最后一个添加的是起点,这时候反转就ok啦。

考虑到字典序,就需要排序啦,影响的也就是拆边的顺序,不可能影响到头尾:

  1. 如果死胡同节点字典序更小,则当前直接进入死胡同。那么死胡同一定是第一个进入结果集的,满足它是一笔画最后一画的条件。你从死胡同递归出来以后,根据字典序去遍历其他的非死胡同节点。这样一定能产生一个有效的路径。
  2. 如果死胡同的字典序更大,则当前递归进入其他的非死胡同节点,那么一定会再次递归回到当前节点而进入死胡同。为什么?其他节点出入度都相同,递归相当于拆边,每个节点出入边都拆相等的次数,一定会回到原点。这种情况下,死胡同仍然为第一个进入结果集的节点。

题目

题目-重新安排行程
在这里插入图片描述

回溯解法

class Solution {
    List<String> res = new ArrayList<>();
    List<String> path = new ArrayList<>();
    public List<String> findItinerary(List<List<String>> tickets) {
        tickets.sort((o1,o2) -> o1.get(1).compareTo(o2.get(1)));
        boolean[] ticketsUsed = new boolean[tickets.size()];
        backtracking("JFK", tickets, ticketsUsed, 0);
        path.add(0,"JFK");
        return path;
    }

    public boolean backtracking(String start, List<List<String>> tickets, boolean[] ticketsUsed, int count){
        if(count == tickets.size()){
            path = new ArrayList(res);
            return true;
        }
        for(int i = 0; i < tickets.size(); i++){
            if(!tickets.get(i).get(0).equals(start) || ticketsUsed[i]){
                continue;                
            }
            res.add(tickets.get(i).get(1));
            ticketsUsed[i] = true;
            if(backtracking(tickets.get(i).get(1), tickets, ticketsUsed, count + 1)){
                return true;
            }
            ticketsUsed[i] = false;
            res.remove(res.size() - 1);
        }
        return false;
    }
}

Hierholzer 算法

class Solution {
    List<String> res = new ArrayList<>();
    public List<String> findItinerary(List<List<String>> tickets) {
        Map<String,PriorityQueue<String>> map = buildGraph(tickets);
        dfs(map, "JFK");
        Collections.reverse(res);
        return res;

    }


    public Map<String, PriorityQueue<String>> buildGraph(List<List<String>> tickets){
        Map<String, PriorityQueue<String>> map = new HashMap<>();
        for(List<String> ticket : tickets){
            String from = ticket.get(0);
            String to = ticket.get(1);
            if(!map.containsKey(from)){
                map.put(from, new PriorityQueue<>((o1,o2) -> {
                    return o1.compareTo(o2);
                }));
            }
            map.get(from).offer(to);
        }
        return map;
    }

    public void dfs(Map<String, PriorityQueue<String>> map, String start){
        if(map.containsKey(start)){
            PriorityQueue<String> nextCityPQ = map.get(start); 
            while(nextCityPQ.size() > 0){
                String nextCity = nextCityPQ.poll();
                dfs(map, nextCity);
            }
        }
        
        res.add(start);
    }
}

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值