1 solutions
-
0
题面描述
在这道题中,我们需要帮助塔子规划从起点星球到终点星球的最短路径,给定的路径由若干通行证定义。输入包括通行证的数量和起点、终点的编号,以及每个通行证的起止星球。输出应为塔子需要经过的星球数量(不包括起点),若无法到达终点,则返回 -1。我们可以使用广度优先搜索(BFS)算法来解决此问题,通过构建星球间的图结构,逐层探索可达星球,以找到最短路径或判断不可达。
思路: bfs
朴素的bfs求最短路的题
算法步骤:
- 图的表示:使用邻接表来表示图。对于每个通行证(边),将起点和终点加入到相应的列表中。
- 初始化:创建一个数组
vis
用于标记每个星球是否被访问过,以及记录到达该星球所需的步数。 - BFS搜索:
- 初始化队列,将起点放入队列。
- 进行循环,直到队列为空。在每一层中,遍历当前层的所有星球,并对每个星球的相邻星球进行处理。
- 如果相邻星球尚未被访问,则更新其访问步数,并将其加入队列。
- 步数在每一层结束时自增,确保每次都能正确计算到达每个星球的最小步数。
- 结果输出:检查终点星球的访问步数,如果仍为 0,则表示不可达,输出 -1;否则输出访问步数。
代码
C++
#include<bits/stdc++.h> using namespace std; // 定义邻接表 vector<vector<int>> edge; int vis[100010]; // 访问数组,用于记录每个星球的访问状态和步数 int m1, m2; // 起点和终点星球编号 int main() { edge.resize(100010); // 初始化邻接表 int n; cin >> n >> m1 >> m2; // 输入通行证数量和起终点编号 // 读取通行证信息,构建图 for (int i = 0; i < n; i++) { int x, y; cin >> x >> y; // 输入每个通行证的起点和终点 edge[x].push_back(y); // 建立有向边 } int step = 0; // 步数计数器 queue<int> qu; // 队列用于 BFS qu.push(m1); // 将起点加入队列 while (!qu.empty()) // 当队列不为空时继续进行 BFS { int sz = qu.size(); // 当前层的节点数量 for (int i = 0; i < sz; i++) { int top = qu.front(); // 获取队列头部元素 qu.pop(); // 弹出队列头部元素 for (int v : edge[top]) // 遍历当前节点的所有邻接节点 { if (vis[v]) // 如果邻接节点已经被访问过 continue; // 跳过该节点 vis[v] = step + 1; // 更新访问步数 qu.push(v); // 将邻接节点加入队列 } } // 步数自增,准备处理下一层节点 step++; } // 判断终点是否被访问过 if (vis[m2] == 0) cout << -1 << endl; // 如果没有访问到终点,输出 -1 else cout << vis[m2] << endl; // 否则输出到达终点的步数 return 0; // 程序结束 }
Python
import sys from collections import deque, defaultdict # 广度优先搜索函数,返回从起点到终点的最短路径长度 def bfs(graph, start, end): # 如果起点和终点相同,直接返回 0 if start == end: return 0 # 初始化队列,存储当前节点和到达该节点的距离 queue = deque([(start, 0)]) # 使用集合来记录已访问的节点 visited = set([start]) # 开始 BFS 循环 while queue: current, distance = queue.popleft() # 弹出队列的第一个元素 # 遍历当前节点的所有邻居 for neighbor in graph[current]: if neighbor not in visited: # 如果邻居节点尚未被访问 if neighbor == end: # 如果找到终点 return distance + 1 # 返回当前距离加一 visited.add(neighbor) # 标记邻居为已访问 queue.append((neighbor, distance + 1)) # 将邻居加入队列,距离加一 return -1 # 如果队列遍历完仍未找到终点,返回 -1 # 主函数 def main(): input = sys.stdin.read # 从标准输入读取所有数据 data = input().split() # 将输入数据按空格分割为列表 index = 0 # 读取通行证数量、起点和终点 n = int(data[index]) # 通行证数量 index += 1 m1 = int(data[index]) # 起点编号 index += 1 m2 = int(data[index]) # 终点编号 index += 1 # 初始化图的邻接表 graph = defaultdict(list) for _ in range(n): u = int(data[index]) # 读取边的起点 index += 1 v = int(data[index]) # 读取边的终点 index += 1 graph[u].append(v) # 将边添加到图中 # 调用 BFS 函数计算从 m1 到 m2 的最短路径 result = bfs(graph, m1, m2) print(result) # 输出结果 # 程序入口 if __name__ == "__main__": main() # 执行主函数
Java
import java.util.*; public class Main { public static void main(String[] args) { Scanner sc = new Scanner(System.in); // 创建输入扫描器 // 读取输入的通行证数量、起点和终点 int n = sc.nextInt(); // 通行证数量 int start = sc.nextInt(); // 起点编号 int end = sc.nextInt(); // 终点编号 // 使用哈希表来存储图的邻接表,键是起点,值是与之相连的终点集合 Map<Integer, Set<Integer>> map = new HashMap<>(); // 读取每个通行证的信息,构建图 for (int i = 0; i < n; i++) { int from = sc.nextInt(); // 通行证的起点 int to = sc.nextInt(); // 通行证的终点 // 获取起点对应的终点集合,如果不存在则创建一个新的集合 Set<Integer> set = map.getOrDefault(from, new HashSet<>()); set.add(to); // 将终点添加到集合中 map.put(from, set); // 更新哈希表 } // 如果起点在图中不存在,直接输出 -1 if(!map.containsKey(start)){ System.out.println(-1); return; } // 初始化队列用于广度优先搜索 Queue<Integer> queue = new LinkedList<>(); queue.add(start); // 将起点加入队列 int cnt = 0; // 步数计数器 Set<Integer> set = new HashSet<>(); // 记录已访问的节点 set.add(start); // 将起点标记为已访问 // 开始广度优先搜索 while (!queue.isEmpty()){ int size = queue.size(); // 当前层节点数量 for (int i = 0; i < size; i++) { int from = queue.poll(); // 从队列中取出一个节点 // 检查是否到达终点 if(from == end){ System.out.println(cnt); // 输出当前步数 return; } // 如果当前节点在图中有邻接节点 if(map.containsKey(from)){ for(int to : map.get(from)){ // 遍历所有邻接节点 // 如果邻接节点尚未被访问 if(!set.contains(to)){ set.add(to); // 标记为已访问 queue.add(to); // 将其加入队列 } } } } cnt++; // 步数自增,进入下一层搜索 } System.out.println(-1); // 如果无法到达终点,输出 -1 } }
- 1
Information
- ID
- 41
- Time
- 2000ms
- Memory
- 512MiB
- Difficulty
- 6
- Tags
- # Submissions
- 409
- Accepted
- 108
- Uploaded By