快递投放问题

题目描述

  • N N N个快递站点用字符串标识,某些站点之间有道路连接。
  • 每个站点有一些包裹要运输,每个站点间的包裹不重复,路上有检查站会导致部分货物无法通行,计算哪些货物无法正常投递?

输入描述

  • 第一行输入 M N M\quad N MN M M M个包裹和 N N N个道路信息
  • 0 ≤ M , N ≤ 100 0\leq M,N \leq 100 0M,N100
  • 检查站禁止通行的包裹如果有多个,则以空格分开

输出描述

  • 输出不能送达的包裹,如package2、package4
  • 如果所有的包裹都能送达则输出:none
  • 输出结果按照升序排列

用例

4 2
package1 A C
package2 A C
package3 B C
package4 A C
A B package1
A C package2

--输出
package2

题目解析

这个题目极其难以理解,文字越少越难理解。

提取关键点

  • 首先注意到数据范围是 [ 0 , 1 0 2 ] [0, 10^2] [0,102]
    • 这个数据范围下,可以重复多次遍历
  • M M M个包裹信息,这快比较好理解,如用例
    • package1 A C:表示了需要把包裹 package1 从站点 A 运送到 站点 C
    • 这里隐藏一个信息,是否存在这样的用例 package1 C A,即把包裹从站点 C 运送到 站点 A
      • 这一点还是要考虑到的
  • 根据题目描述和输入描述
    • 题目描述:有 N N N 个快递站点用字符串标识,某些站点之间有道路连接
    • 输入描述: N N N个道路信息
    • 这两个 N N N的意义是否相同?这里肯定是不相同的,为什么?
      • 因为一个道路可以连接两个站点
    • 那么根据输入描述,根据用例中的道路信息可以知道快递站点之间的关系如下。
    • 快递投放问题_第1张图片
    • 这里根据用例 package3 B C 可以得到一个关键信息,快递投放可以通过站点之间进行中转
    • 至此,分析完毕,问题转化成了求图中是否存在有效路径的问题.

show code

package com.hw;

import java.util.*;

/**
 * desc :
 * 

* create time : 2023/8/17 17:23 */ public class DeliverPathFinderBetter { public static void main(String[] args) { Scanner in = new Scanner(System.in); String[] split = in.nextLine().split(" "); // M 个包裹. int M = Integer.parseInt(split[0]); // N 个道路信息. int N = Integer.parseInt(split[1]); // 包裹信息,表示包裹需要从 一个站点运输到另一个站点. String[][] pkgMsgS = new String[M][]; for (int i = 0; i < M; i++) { pkgMsgS[i] = in.nextLine().split(" "); } // 道路信息以及在目标道路上禁止运送的包裹信息. String[][] banPkgS = new String[N][]; for (int i = 0; i < N; i++) { banPkgS[i] = in.nextLine().split(" "); } deliverPathFinderBetter(pkgMsgS, banPkgS); } private static void deliverPathFinderBetter(String[][] pkgMsgS, String[][] banPkgS) { // 包裹运送信息--适合用 map 来存储 Map<String, String[]> deliverMap = new HashMap<>(); for (String[] pkgMsg : pkgMsgS) { String[] startToEnd = {pkgMsg[1], pkgMsg[2]}; // 包裹不能重复,直接 put. deliverMap.put(pkgMsg[0], startToEnd); } // 根据道路信息,构造图数据. Map<String, List<String>> graph = new HashMap<>(); // 用一个map,保存 禁止运输的 包裹信息. Map<String, Set<String>> banMap = new HashMap<>(); // 处理数据. for (String[] banPkg : banPkgS) { String site1 = banPkg[0]; String site2 = banPkg[1]; String[] bans = Arrays.copyOfRange(banPkg, 2, banPkg.length); // 建图数据结构. graph.computeIfAbsent(site1, k -> new ArrayList<>()).add(site2); graph.computeIfAbsent(site2, k -> new ArrayList<>()).add(site1); String key = (site1.charAt(0) - 'A') < (site2.charAt(0) - 'A') ? (site1 + "-" + site2) : (site2 + "-" + site1); // 禁止通行的包裹列表 banMap.computeIfAbsent(key, k -> new HashSet<>()).addAll(Arrays.asList(bans)); } dealPkgS(deliverMap, graph, banMap); } private static void dealPkgS(Map<String, String[]> deliverMap, Map<String, List<String>> graph, Map<String, Set<String>> banMap) { Set<String> unreachablePackages = new TreeSet<>(); for (String pkg : deliverMap.keySet()) { // 当前将要运送的包裹是 pkg, 需要运送其从站点 start 到 end . String[] path = deliverMap.get(pkg); String start = path[0].charAt(0) - 'A' < path[1].charAt(0) - 'A' ? path[0] : path[1]; String end = path[0].charAt(0) - 'A' < path[1].charAt(0) - 'A' ? path[1] : path[0]; // 查看是否存在可通行的路径. // 用一个set记录路径——即所到达的站点. Set<String> visited = new HashSet<>(); if(!dfs(pkg, start, end, graph, visited, banMap)) { unreachablePackages.add(pkg); } } if(unreachablePackages.size() == 0) { System.out.println("none"); } else { for (String unreachablePackage : unreachablePackages) { System.out.print(unreachablePackage + " "); } } } private static boolean dfs(String pkg, String start, String end, Map<String, List<String>> graph, Set<String> visited, Map<String, Set<String>> banMap) { if (start.equals(end)) { // 到达了目标站点,那么这个时候返回 true ,表示该包裹可以到达目标站点. return true; } visited.add(start); for (String nextSite : graph.getOrDefault(start, Collections.emptyList())) { if(visited.contains(nextSite)) { // 去过的站点跳过. continue; } String key = start.charAt(0) - 'A' < nextSite.charAt(0) - 'A' ? start + "-" + nextSite : nextSite + "-" + start; if(banMap.containsKey(key) && banMap.get(key).contains(pkg)) { // 当前路径不允许当前包裹通过. continue; } if(dfs(pkg, nextSite, end, graph, visited, banMap)) { return true; } } return false; } }

你可能感兴趣的:(算法学习心得记录,算法)