7-135 过年了,回家吧 (35分)

小CC的家离学校有1000多公里,坐火车要数十个小时。每年春运之时,小CC总要绞尽脑汁寻找最合适的换乘路线。

小CC的换乘问题抽象如下:

地图上有N个城市,M条交通路线将城市两两相连。小CC需要经过若干条交通路线,从城市S回到城市T。途径每条交通路线都会消耗一定时间,在中转城市换乘也需要消耗一定时间,起点和终点的换乘时间不计算在内。现在请你编写程序,帮小CC规划回家的路,这条路必须是耗时最短的路径,如果有耗时相同的多条路径,选择其中换乘最少的一条。

例如,小CC要从厦门回到大同,下图是小CC回家时的线路图,图中的方块表示换乘时间,线路上的数字表示线路的旅途时间。

(本图仅作示意,不代表真实旅行时间和实际地理位置)

从图中可以看出,有多条路径可以选择,但是耗时最短的路径(耗时375)只有两条:

厦门->北京->大同,路途时间227+70,换乘时间78;
厦门->南昌->郑州->大同,旅途时间65+64+125,换乘时间40+81。
此时,小CC会选择换乘次数较少的第1条线路。

输入格式:
第一行为1个正整数N≤500,表示城市个数。
然后是N行,每行依次是城市名称和换乘时间。城市名称不超过40个字符,由大小写字母组成,换乘时间是不大于10^4的正整数。
接下来是一个正整数M≤3N,表示交通路线条数。
接着M行,每行三个元素,依次是两个城市名称和路线耗时(不大于10^4
​​ 的正整数)。
最后一行依次给出起点S和目的地T的城市名称。
输出格式:
如果存在一条从起点到终点耗时最短的路线:
第一行输出耗时(起点终点的中转时间不计算在内)。
第二行按照从起点到终点的顺序输出沿途城市(包括起点终点),用->链接。
如果有多条耗时最短的路线,输出中转次数最少的一条。
如果不存在一条从起点到终点的路线:
输出一行:“Why not go home by plane?"

输入样例1:
示意图中的例子。

10
Datong 52
Xuzhou 87
Hefei 71
Nanchang 40
Zhengzhou 81
Shijiazhuang 56
Taiyuan 45
Nanjing 43
Beijing 78
Xiamen 55
22
Xiamen Beijing 227
Beijing Nanjing 170
Xiamen Hefei 95
Zhengzhou Shijiazhuang 41
Beijing Datong 70
Beijing Taiyuan 34
Taiyuan Datong 65
Taiyuan Shijiazhuang 19
Nanjing Hefei 10
Xuzhou Nanchang 102
Beijing Shijiazhuang 25
Xuzhou Beijing 157
Zhengzhou Xuzhou 37
Xiamen Xuzhou 139
Beijing Nanchang 201
Nanchang Xiamen 65
Zhengzhou Nanchang 64
Datong Zhengzhou 125
Hefei Xuzhou 46
Shijiazhuang Nanjing 198
Taiyuan Zhengzhou 43
Hefei Beijing 165
Xiamen Datong

输出样例1:

375
Xiamen->Beijing->Datong

输入样例2:
非连通图。仅有两条边,乌鲁木齐(新疆)-阿拉山口(新疆),乌兰察布(原称集宁,内蒙古)-呼和浩特(内蒙古)。不存在阿拉山口-乌兰察布路径。

4
Alashankou 50
Urumchi 65
Hohhot 69
Ulanqab 75
2
Urumchi Alashankou 96
Hohhot Ulanqab 125
Alashankou Ulanqab

输出样例2:

Why not go home by plane?

思路
1. 将各个地点名转换为编号,方便进行处理(使用map<string,int>对字符串标记)
2. 标记好了,就可以进行dijkstra算法。(该题的dijkstra跟bfs有点像,用的是优先队列进行处理的,目的是找出权值最小且经过结点数最小的路径)、
具体的解释见代码。

代码参考某位前辈的博客: https://www.jianshu.com/p/24ac21272508

AC代码:

#include<bits/stdc++.h>
#define inf 1e9
using namespace std;
map<string,int> mp;
int d[520][520],dis[520];
int pre[520], cnt[520], output[520];string re[520];
int n,m,start,goal,sum=0,minn=1e9,flag=0;struct Node{int pos, cost, num, from;Node(int a, int b, int c, int d){  //构造函数,方便赋值 pos=a,cost=b,num=c,from=d;}
};struct cmp{   //优先队列排序方式(即优先选择最优路径,耗时最少或者耗时相同转乘少) bool operator() (Node &x, Node &y){if(x.cost!=y.cost) return x.cost<y.cost;return x.num<y.num;}
};void dijkstra(int start, int goal){dis[start]=0;pre[start]=start;priority_queue<Node, vector<Node>, cmp> q;q.push(Node(start,0,0,start));while(!q.empty()){int p=q.top().pos;//当前位置int t=q.top().cost; //当达该位置的总耗时 int sum=q.top().num;//到达该位置,经过的结点数;int f=q.top().from; //该位置前一位置q.pop();if(dis[p]<t||(dis[p]==t&&cnt[p]<=sum)) continue; //选出符合条件的路线(耗时最短,或者耗时相同转乘少) dis[p]=t;//记录时间 pre[p]=f;  //记录p站的前一站 cnt[p]=sum; //记录到达p站,共经过多少站 for(int i=0; i<n; i++){if(d[p][i]!=inf&&p!=i){int newt=t+d[p][i]+d[i][i];  //经过p站到达i站所用时间  if(i==goal) newt -= d[i][i];  //到达目标,减去最后换乘时间 if(newt>dis[i]) continue; //这个新路径耗时大于之前的乘坐方式,则跳过 q.push(Node(i, newt, sum+1, p)); }}       }
} int main()
{fill(dis,dis+520,inf);fill(d[0],d[0]+520*520,inf); fill(cnt,cnt+520, inf);cin>>n;int x,dist,ans=inf;string s,s1,s2;for(int i=0; i<n; i++){cin>>s>>x;mp[s]=i;//对字符串编号 re[i]=s;//再根据编号得到对应的字符串 d[i][i]=x;}cin>>m;for(int i=0; i<m; i++){cin>>s1>>s2>>dist;d[mp[s1]][mp[s2]]=d[mp[s2]][mp[s1]]=dist;}cin>>s1>>s2;dijkstra(mp[s1],mp[s2]);  //求出到最终的最短路径 ans=dis[mp[s2]];if(ans!=inf){cout<<ans<<endl;int k=0, place=mp[s2];while(place!=mp[s1]){   //当该站前面不是起点站,不停的回退 output[k++] = place; //output保存从路径 place=pre[place];}cout<<s1;for(int i=k-1; i>=0; i--)cout<<"->"<<re[output[i]];cout<<endl;}else{cout<<"Why not go home by plane?"<<endl;}return 0;
}

个人总结
题目要求的是最短路径,很容易能想到使用dijkstra来求,但是要保存走过的路径,所以开始我就不知道怎么用dijkstra了。于是使用了dfs,搜了半天提交都是有问题的,而且还会超时。最后看来其他前辈的文章才知道,dijkstra怎么保存路径的,佩服佩服,我要继续加油啦。
这里也贴上未AC的dfs 代码:(ps:如果有前辈知道我这dfs错在哪里,希望前辈指导,嘿嘿)

#include<bits/stdc++.h>
using namespace std;
map<string,int> mp;
int d[520][520], vis[520][520];
string re[520];
int n,m,start,goal,sum=0,minn=1e9,flag=0;
stack<int> st,ans,temp;  //ans保存答案路径 void dfs(int x){st.push(x);  //保存动态路径 if(x==goal){flag=1;if(sum<minn||(sum==minn&&st.size()<ans.size())){minn=sum;while(!ans.empty()) ans.pop();while(!temp.empty()) temp.pop();while(!st.empty()){ans.push(st.top());temp.push(st.top());st.pop();}             while(!temp.empty()){st.push(temp.top());temp.pop();}}return;       }for(int i=0; i<n; i++){if(!vis[x][i]&&d[x][i]&&x!=i){vis[x][i]=1;vis[i][x]=1; sum+=d[x][i];dfs(i);sum-=d[x][i];vis[x][i]=0;vis[i][x]=0;}}st.pop();
}int main()
{cin>>n;int x,dis;string s,s1,s2;for(int i=0; i<n; i++){cin>>s>>x;mp[s]=i;re[i]=s;//反编号 d[i][i]=x;}cin>>m;for(int i=0; i<m; i++){cin>>s1>>s2>>dis;d[mp[s1]][mp[s2]]=dis+d[mp[s2]][mp[s2]];//路程耗时和转乘耗时 d[mp[s2]][mp[s1]]=dis+d[mp[s2]][mp[s2]]; }cin>>s1>>s2;start=mp[s1],goal=mp[s2];for(int i=0; i<n; i++){if(d[start][i]&&!vis[start][i]&&start!=i){sum=d[start][i]; while(!st.empty()) st.pop();vis[start][i]=1;vis[i][start]=1; dfs(i);vis[start][i]=0;vis[i][start]=0; }}if(!flag) cout<<"Why not go home by plane?"<<endl;else{cout<<minn-d[goal][goal]<<endl;  //减去终点换成的时间,因为前面计算时加上了,所以最后要减一下 cout<<re[start];while(!ans.empty()){cout<<"->";cout<<re[ans.top()];ans.pop();} }return 0;
}

欢迎大家批评改正!!!

PTA:7-135 过年了,回家吧 (35分)(天梯赛,dijkstra+解析)相关推荐

  1. L1-057 PTA使我精神焕发 (5 分) 天梯赛 详解

    以上是湖北经济学院同学的大作.本题就请你用汉语拼音输出这句话. 输入格式: 本题没有输入. 输出格式: 在一行中按照样例输出,以惊叹号结尾. 输入样例: 无 结尾无空行 输出样例: PTA shi3 ...

  2. PTA|团体程序设计天梯赛-练习题库集

    文章目录 关于爬取脚本的编写 L1-001 Hello World! (5 分) L1-002 打印沙漏 (15 分) L1-003 个位数统计 (15 分) L1-004 计算摄氏温度 (5 分) ...

  3. 团体设计天梯赛-PTA练习题

    前言 所有题目来源:团体程序设计天梯赛-练习集 https://pintia.cn/problem-sets/994805046380707840/problems/type/7 然后CSDN审核不通 ...

  4. [PTA]2021天梯赛-总决赛 L1题解合集

    文章目录 前言说明 题解 人与神 (5 分) 两小时学完C语言 (5 分) 强迫症 (10 分) 降价提醒机器人 (10 分) 大笨钟的心情 (15 分) 吉老师的回归 (15 分) 天梯赛的善良 ( ...

  5. PTA 1002 Business (35分)

    想试试PTA Top Level的难度,然后随便来了一题~ 1002 Business (35分) As the manager of your company, you have to carefu ...

  6. 过年不回家,压岁钱、份子钱省下来了吗?

    来源/中新经纬 ID/jwview 作者/赵佳然 "今年春节不能回家,终于不用给亲戚家20多个小孩发红包了.往年一发就是一万多,虽然见不着家人,但能省下一笔费用,也算是安慰."谈及 ...

  7. 某程序员爆料:今年滴滴全员发1200元红包,包括保洁人员,过年不回家还有666元留守红包,良心企业!...

    因为疫情原因,许多公司号召员工过年不回家,并采取各种措施留住员工. 一个滴滴员工发帖表扬自家公司,说滴滴今年全员都有1200元红包,包含实习生和保洁阿姨大叔,过年不回家的还有666元的留守红包.楼主深 ...

  8. PTA的天梯赛与PAT练习记录

    PTA的天梯赛与PAT练习记录 L1-078吉老师的回归 L1-080乘法口诀数列 L2-005集合相似度 L2-014列车调度 L2-025分而治之 L2-029特立独行的幸福 L2-030冰岛人 ...

  9. PTA|团体程序设计天梯赛-练习题目题解锦集(C/C++)(持续更新中……)

    PTA|团体程序设计天梯赛-练习题目题解锦集(持续更新中) 实现语言:C/C++:      欢迎各位看官交流讨论.指导题解错误:或者分享更快的方法!! 题目链接:https://pintia.cn/ ...

最新文章

  1. php 5.2 模块路径,5.2 模块和操作
  2. python3 struct模块 处理二进制 pack unpack用法
  3. 怎么连接屏幕_触控一体机怎么实现无线投屏功能
  4. 复杂XML的解析及组装
  5. TT和LG编程设计模式之代理
  6. 惊!MySQL官网巨变,下载被取消
  7. 文案月薪3w?月薪10w的设计大神笑而不语
  8. 阿酷快捷键怎么使用_必须收藏!Linux用户必须知道的常用终端快捷键
  9. Problem B: C语言习题 学生成绩输入和输出
  10. layui option 动态添加_layuiselect如何动态添加option
  11. linux g++开启C++11/14支持
  12. 《搭建Centos7之一》
  13. 全面规范的软件需求可以规避项目风险
  14. BAT会看上哪样的中小公司程序员? 1
  15. 【英语魔法俱乐部——读书笔记】 3 高级句型-简化从句倒装句(Reduced Clauses、Inverted Sentences) 【完结】...
  16. hustOJ使用问题
  17. html5快捷键自动对齐,【答疑】pr自动对齐的快捷键是什么 - 视频教程线上学
  18. Where are Docker images stored? (杂译)
  19. 匿名管道(Pipe)和命名管道(FIFO)
  20. 单体测试使用Assert.assertThat(expected,Matcher matcher)来对比结果和预期

热门文章

  1. C++使用VARIANT实现二维数组的操作、怎么使用COleSafeArray实现二维数组将字符串写入excel
  2. js限制文本框只能输入数字方法
  3. 改变数据库中的True/False的小窍门
  4. LocalDateTime获取时间戳、LocalDateTime与String互转、Date与LocalDateTime互转(Java8 特性)
  5. mysql phpmyadmin配置文件_phpmyadmin 配置文件详细的解释说明
  6. Wireshark入门与进阶系列十二之IP冲突
  7. 网秦:私有化未了、借壳上市未成,集体诉讼连环爆发
  8. RT-Thread线程管理以及内核裁剪
  9. 求字符串长度【三种解题思路】
  10. Reducer buckets have been rebuilt in this iteration.