快递投放问题
华为OD机试双机位C卷 - 华为OD上机考试双机位C卷 200分题型
华为OD机试双机位C卷真题目录点击查看: 华为OD机试双机位C卷真题题库目录|机考题库 + 算法考点详解
题目描述
有N个快递站点用字符串标识,某些站点之间有道路连接。
每个站点有一些包裹要运输,每个站点间的包裹不重复,路上有检查站会导致部分货物无法通行,计算哪些货物无法正常投递?
输入描述
- 第一行输入M N,M个包裹N个道路信息.
- 0<=M,N<=100,
- 检查站禁止通行的包裹如果有多个以空格分开
输出描述
- 输出不能送达的包裹,如:package2 package4,
- 如果所有包裹都可以送达则输出:none,
- 输出结果按照升序排列。
用例1
输入
none
4 2
package1 A C
package2 A C
package3 B C
package4 A C
A B package1
A C package2
输出
none
package2
题解
思路:BFS
- 这道题题目太短并且描述也不太准确,通过测试案例和题意结合来看我个人认为的意思: 给定所有包裹的起点和目标终点。然后给出n条线路,其中每条线路表示这两个站点互连,同时这条线路可以禁止某些包裹通过。
- 通过1的分析这道题就转换为带有限制的无向图,判断指定路径是否可达。
- 通过记录线路站点并且禁止包裹,循环使用BFS判断每个包裹是否能从起点到达终点,不可达的包裹加入结果数组。
- 如果不存在不可达包裹,输出
none. 否则升序排列之后,按照空格分割输出。
c++
c++
#include<iostream>
#include<vector>
#include<string>
#include <utility>
#include <sstream>
#include<algorithm>
#include<cmath>
#include<map>
#include<unordered_set>
#include<set>
#include<queue>
using namespace std;
// 边结构
struct Edge {
string to; // 目标站点
unordered_set<string> banned; // 禁止通过的包裹
};
// 包裹结构
struct Package {
string name;
string start;
string end;
};
// 通用 切割函数 函数 将字符串str根据delimiter进行切割
vector<string> split(const string& str, const string& delimiter) {
vector<string> result;
size_t start = 0;
size_t end = str.find(delimiter);
while (end != string::npos) {
result.push_back(str.substr(start, end - start));
start = end + delimiter.length();
end = str.find(delimiter, start);
}
// 添加最后一个部分
result.push_back(str.substr(start));
return result;
}
int main() {
ios::sync_with_stdio(false);
cin.tie(nullptr);
int m,n;
cin >> m >> n;
// 忽略换行符
cin.ignore();
vector<Package> packages(m);
for (int i = 0; i < m; i++) {
string input;
getline(cin, input);
vector<string> tmp = split(input, " ");
packages[i].name = tmp[0];
packages[i].start = tmp[1];
packages[i].end = tmp[2];
}
// 存储每个包裹被进制的路线
map<string, vector<Edge>> graph;
for (int i = 0; i < n; i++) {
string input;
getline(cin, input);
vector<string> tmp = split(input, " ");
unordered_set<string> banned(tmp.begin()+2, tmp.end());
// 无向图,双向加边
graph[tmp[0]].push_back({tmp[1], banned});
graph[tmp[1]].push_back({tmp[0], banned});
}
vector<string> res;
// BFS判断每个包裹是否可到达
for (auto &pkg : packages) {
queue<string> q;
unordered_set<string> visited;
q.push(pkg.start);
visited.insert(pkg.start);
bool canReach = false;
while (!q.empty()) {
string cur = q.front();
q.pop();
if (cur == pkg.end) {
canReach = true;
break;
}
if (!graph.count(cur)) continue;
for (auto &edge : graph[cur]) {
// 如果这条路禁止该包裹,跳过
if (edge.banned.count(pkg.name)) continue;
if (!visited.count(edge.to)) {
visited.insert(edge.to);
q.push(edge.to);
}
}
}
if(!canReach) {
res.push_back(pkg.name);
}
}
// 都可送达
if (res.empty()) {
cout << "none";
return 0;
}
// 升序
sort(res.begin(), res.end());
// 输出结果
for (int i = 0; i < res.size(); i++) {
if (i != 0) {
cout << " ";
}
cout << res[i];
}
return 0;
}
JAVA
JAVA
import java.io.*;
import java.util.*;
// 边结构
class Edge {
String to; // 目标站点
Set<String> banned; // 禁止通过的包裹
Edge(String to, Set<String> banned) {
this.to = to;
this.banned = banned;
}
}
// 包裹结构
class PackageInfo {
String name;
String start;
String end;
}
public class Main {
public static void main(String[] args) throws Exception {
BufferedReader br = new BufferedReader(new InputStreamReader(System.in));
StringTokenizer st = new StringTokenizer(br.readLine());
int m = Integer.parseInt(st.nextToken());
int n = Integer.parseInt(st.nextToken());
List<PackageInfo> packages = new ArrayList<>();
// 读取包裹信息
for (int i = 0; i < m; i++) {
st = new StringTokenizer(br.readLine());
PackageInfo pkg = new PackageInfo();
pkg.name = st.nextToken();
pkg.start = st.nextToken();
pkg.end = st.nextToken();
packages.add(pkg);
}
// 图结构
Map<String, List<Edge>> graph = new HashMap<>();
// 读取道路信息
for (int i = 0; i < n; i++) {
st = new StringTokenizer(br.readLine());
String u = st.nextToken();
String v = st.nextToken();
Set<String> banned = new HashSet<>();
while (st.hasMoreTokens()) {
banned.add(st.nextToken());
}
graph.computeIfAbsent(u, k -> new ArrayList<>()).add(new Edge(v, banned));
graph.computeIfAbsent(v, k -> new ArrayList<>()).add(new Edge(u, banned));
}
List<String> res = new ArrayList<>();
// BFS 判断每个包裹是否可达
for (PackageInfo pkg : packages) {
Queue<String> q = new LinkedList<>();
Set<String> visited = new HashSet<>();
q.offer(pkg.start);
visited.add(pkg.start);
boolean canReach = false;
while (!q.isEmpty()) {
String cur = q.poll();
if (cur.equals(pkg.end)) {
canReach = true;
break;
}
if (!graph.containsKey(cur)) continue;
for (Edge e : graph.get(cur)) {
// 该路径禁止
if (e.banned.contains(pkg.name)) continue;
if (!visited.contains(e.to)) {
visited.add(e.to);
q.offer(e.to);
}
}
}
if (!canReach) {
res.add(pkg.name);
}
}
if (res.isEmpty()) {
System.out.print("none");
} else {
Collections.sort(res);
System.out.print(String.join(" ", res));
}
}
}
Python
python
from collections import deque, defaultdict
# 读取 m, n
m, n = map(int, input().split())
# 读取包裹信息
packages = []
for _ in range(m):
name, start, end = input().split()
packages.append((name, start, end))
# 图结构:站点 -> [(目标站点, 禁止包裹集合)]
graph = defaultdict(list)
# 读取道路信息
for _ in range(n):
parts = input().split()
u, v = parts[0], parts[1]
banned = set(parts[2:])
graph[u].append((v, banned))
graph[v].append((u, banned))
res = []
# BFS 判断每个包裹是否可达
for name, start, end in packages:
q = deque([start])
visited = {start}
can_reach = False
while q:
cur = q.popleft()
if cur == end:
can_reach = True
break
if cur not in graph:
continue
for nxt, banned in graph[cur]:
# 路径禁止通过
if name in banned:
continue
if nxt not in visited:
visited.add(nxt)
q.append(nxt)
if not can_reach:
res.append(name)
# 输出结果
if not res:
print("none")
else:
res.sort()
print(" ".join(res))
JavaScript
js
// ACM 模式(Node.js + readline)
const readline = require('readline');
const rl = readline.createInterface({
input: process.stdin,
output: process.stdout
});
let lines = [];
rl.on('line', line => {
lines.push(line.trim());
});
rl.on('close', () => {
let idx = 0;
// 读取 m, n
let [m, n] = lines[idx++].split(/\s+/).map(Number);
// 读取包裹信息
let packages = [];
for (let i = 0; i < m; i++) {
let [name, start, end] = lines[idx++].split(/\s+/);
packages.push({ name, start, end });
}
// 图结构
let graph = new Map();
// 读取道路信息
for (let i = 0; i < n; i++) {
let parts = lines[idx++].split(/\s+/);
let u = parts[0], v = parts[1];
let banned = new Set(parts.slice(2));
if (!graph.has(u)) graph.set(u, []);
if (!graph.has(v)) graph.set(v, []);
graph.get(u).push({ to: v, banned });
graph.get(v).push({ to: u, banned });
}
let res = [];
// BFS 判断每个包裹是否可达
for (let pkg of packages) {
let queue = [pkg.start];
let visited = new Set([pkg.start]);
let canReach = false;
while (queue.length > 0) {
let cur = queue.shift();
if (cur === pkg.end) {
canReach = true;
break;
}
if (!graph.has(cur)) continue;
for (let edge of graph.get(cur)) {
// 如果这条路禁止该包裹,跳过
if (edge.banned.has(pkg.name)) continue;
if (!visited.has(edge.to)) {
visited.add(edge.to);
queue.push(edge.to);
}
}
}
if (!canReach) {
res.push(pkg.name);
}
}
// 输出结果
if (res.length === 0) {
console.log("none");
} else {
res.sort();
console.log(res.join(" "));
}
});
Go
go
package main
import (
"bufio"
"fmt"
"os"
"sort"
"strconv"
"strings"
)
// 边结构
type Edge struct {
to string
banned map[string]bool
}
// 包裹结构
type Package struct {
name string
start string
end string
}
func main() {
reader := bufio.NewReader(os.Stdin)
// 读取第一行:m n
line, _ := reader.ReadString('\n')
line = strings.TrimSpace(line)
parts := strings.Fields(line)
m, _ := strconv.Atoi(parts[0])
n, _ := strconv.Atoi(parts[1])
// 读取包裹信息
packages := make([]Package, m)
for i := 0; i < m; i++ {
line, _ = reader.ReadString('\n')
parts = strings.Fields(line)
packages[i] = Package{
name: parts[0],
start: parts[1],
end: parts[2],
}
}
// 图结构
graph := make(map[string][]Edge)
// 读取道路信息
for i := 0; i < n; i++ {
line, _ = reader.ReadString('\n')
parts = strings.Fields(line)
u, v := parts[0], parts[1]
banned := make(map[string]bool)
for _, p := range parts[2:] {
banned[p] = true
}
graph[u] = append(graph[u], Edge{to: v, banned: banned})
graph[v] = append(graph[v], Edge{to: u, banned: banned})
}
res := []string{}
// BFS 判断每个包裹是否可达
for _, pkg := range packages {
queue := []string{pkg.start}
visited := map[string]bool{pkg.start: true}
canReach := false
for len(queue) > 0 {
cur := queue[0]
queue = queue[1:]
if cur == pkg.end {
canReach = true
break
}
for _, e := range graph[cur] {
// 如果这条路禁止该包裹,跳过
if e.banned[pkg.name] {
continue
}
if !visited[e.to] {
visited[e.to] = true
queue = append(queue, e.to)
}
}
}
if !canReach {
res = append(res, pkg.name)
}
}
// 输出结果
if len(res) == 0 {
fmt.Print("none")
} else {
sort.Strings(res)
fmt.Print(strings.Join(res, " "))
}
}