PAT_甲级_1131 Subway Map
题目大意:
给一个无向图,求出从一点到另外一点的最短路径,这里的最短,指的是从起点到终点所经历的点的数目最少,如果有多条,输出中转站点最少的。
算法思路:
一开始想到的是用Dijkstra算法求解该问题,但是Dijkstra算法更适合求解第一标尺为边权相关问题,所以想到了DFS,并设置其参数depth,用来记录在从起点到终点的遍历过程中所经历的结点个数,然后采用全局量minDepth保存最小的depth,为了方便判断是否是中转结点问题,使用邻接矩阵存储两个连接的点的边对应的线路,比如2000与2001连通,该边是Line# 4的一部分,则G[2000][2001]=4;
使用全局变量$minTranNum$记录乘坐的最少线路数目。
DFS遍历方法:
DFS函数中设置参数为当前结点st,终点e和深度depth,使用vector<int> result
保存最优的路径,vector<int> path
暂存当前路径, 首先访问当前节点(保存到path中,并设置访问标记为true),然后判断是否到达终点,如果是,首先计算当前路径的中转节点数目,这里的计算方法是使用一个set集合$diffLines$添加所有的 线路,其大小就是乘坐的线路数目(其大小减一就是中转节点数目),如果minDepth>depth
说明当前路径更短,那么就更新最优路径和最优距离和乘坐线路数目,如果 长度相同但是乘坐的线路最少,那么更新最优路径和乘坐线路数目,最后回溯。如果没有到达终点,就递归遍历每一个没有访问的领接点,如果所有的领接点都已经访问完毕, 那么就回溯。
注意点:
- 1、每一次查询都得将全局变量minDepth,minTranNum,visited初始化。
- 2、如果程序没有报错,没有输出结果,查看是否DFS函数有回退操作(
path.pop_back(),visited[st]=false
)
提交结果:
AC代码:
#include<cstdio>
#include<vector>
#include<unordered_set>
#include<cstring>
using namespace std;
int G[10000][10000];//G[i][j]=4表示i和j相连接的边在第4条地铁上
vector<int> path;// 暂存当前搜索到的路径
vector<int> result;// 最优路径
vector<int> Adj[10000];// 邻接表
bool visited[10000];
int minDepth;// 最短长度
int minTranNum;//乘坐的最少线路数目
void DFS(int st, int e, int depth){
// 首先访问当前节点
path.push_back(st);
visited[st] = true;
if(st == e){
// 到达终点
// 计算乘坐的线路数目
unordered_set<int> diffLines;// 不同的线路数目
for (int i = 0; i < path.size() - 1; ++i) {
diffLines.insert(G[path[i]][path[i+1]]);
}
if(minDepth>depth){
// 当前路径更短
result = path;
minDepth = depth;
minTranNum = diffLines.size();
} else if(minDepth==depth&&minTranNum>diffLines.size()){
// 长度相同,但是中转次数最少
result = path;
minTranNum = diffLines.size();
}
// 回溯
path.pop_back();
visited[st] = false;
return;
}
// 访问每一个领接点
for (int next : Adj[st]) {
// 领接点
if(!visited[next]){
DFS(next, e, depth + 1);
}
}
path.pop_back();// 回溯
visited[st] = false;
}
void print(int start,int end){
printf("%d\n",minDepth);
int current_line = G[result[0]][result[1]];// 当前线路
int s = start;// 乘坐当前线路的起点
for (int i = 1; i < result.size()-1; ++i) {
if(G[result[i]][result[i+1]]!=current_line){
// i为换乘站
printf("Take Line#%d from %04d to %04d.\n",current_line,s,result[i]);
s = result[i];
current_line = G[result[i]][result[i+1]];
}
}
// 一直没有换乘或者当前位最后一次中转地铁线
printf("Take Line#%d from %04d to %04d.\n",current_line,s,end);
}
int main(){
int N;
scanf("%d",&N);
for (int i = 0; i < N; ++i) {
int M;
scanf("%d",&M);
int a,b;
for (int j = 0; j < M; ++j) {
if(j==0){
scanf("%d",&a);
} else {
scanf("%d",&b);
G[a][b] = G[b][a] = i+1;
Adj[a].push_back(b);
Adj[b].push_back(a);
a = b;
}
}
}
int K;
scanf("%d",&K);
int start,end;
for (int k = 0; k < K; ++k) {
scanf("%d %d", &start, &end);
// 每次查询都得初始化
minDepth = 0x3fffffff;
minTranNum = 0x3fffffff;
memset(visited,0, sizeof(visited));
path.clear();
result.clear();
DFS(start, end, 0);
print(start, end);// 输出出行方案
}
return 0;
}
推荐阅读
reactor模式
IO线程模型概述目前的IO线程处理模型一般可以分为以下三类单线程阻塞I/O服务模型多线程阻塞IO服务模型Reactor模式根据Reactor的数量和处理资源池线程的数量不同,Reactor模式有如下3种典型的实现单Reactor单线程...
乔梓鑫赞 2阅读 4.5k评论 2
程序员适合创业吗?
大家好,我是良许。从去年 12 月开始,我已经在视频号、抖音等主流视频平台上连续更新视频到现在,并得到了不错的评价。每个视频都花了很多时间精力用心制作,欢迎大家关注哦~考虑到有些小伙伴没有看过我的视频,...
良许赞 3阅读 1.3k
比cat更好用的命令!
但 cat 命令两个很重大的缺陷:1. 不能语法高亮输出;2. 文本太长的话无法翻页输出。正是这两个不足,使得 cat 只能用来查看行数不多的小文件。
良许赞 2阅读 704
DBoS 系统说明
程序员TianSong以单片机开发入门,后续又做了 Qt 相关工作,有时间后开始进行 linux 相关的学习,恰巧在二一年十一月份,百问网的韦东山老师进行了三个月的 linux 驱动直播,于是有了开发 DBoS 的念头。
TianSong赞 1阅读 1.2k
【Qt】简单桌面
[链接]简介简单桌面是一款小巧便捷的桌面背景管理软件。由编程爱好者个人开发,不收集使用者个人信息、不连接网络、不弹窗。下载功能支持单静态图片及多静态图片轮播(轮播时间可设置)支持GIF动画背景支持视频背...
TianSong赞 3阅读 2.2k
良许翻天覆地的2022年
大家好,我是良许,新年快乐呀~在我女室友坚持不懈的努力之下,2022年的最后一天我终于被她传染了,阳了~此时的我,正顶着37多度的低烧写下这篇年终总结。2022年,对于大多数人而言,封控是主旋律——不停地核酸,...
良许赞 2阅读 786评论 1
一个Bug让人类科技倒退几十年?
大家好,我是良许。前几天在直播的时候,问了直播间的小伙伴有没人知道「千年虫」这种神奇的「生物」的,居然没有一人能够答得上来的。所以,今天就跟大家科普一下这个人类历史上最大的 Bug 。1. 全世界的恐慌一...
良许阅读 1.4k
**粗体** _斜体_ [链接](http://example.com) `代码` - 列表 > 引用
。你还可以使用@
来通知其他用户。