• 1018 Public Bike Management (30) & 1030 Travel Plan (30)


    目录

    🧡1018 Public Bike Management

    解析

    易错点

    代码

    🧡1030 Travel Plan

    解析

    易错点

    代码


    💟这里是CS大白话专场,让枯燥的学习变得有趣!

    💟没有对象不要怕,我们new一个出来,每天对ta说不尽情话!

    💟好记性不如烂键盘,自己总结不如收藏别人!

    💌1018和1030这两个求最短路径的题都需要用Dijkstra+DFS算法,常被PAT用做压轴题,背也要背下来!

    🧡1018 Public Bike Management

    题目链接:PTA | 程序设计类实验辅助教学平台

    解析

    💌有N个站点,站点间交通时长T,每个站点最多容纳Cmax个自行车,最优状态是放置Cmax/2辆自行车。给出问题站点Sp,求出从源点0到问题站点的最短路径,路径上的站点都要重新调整到最优状态,若有多条路径,选择需要从源点send最少自行车的路径,若不需要send,选择返回时需要带回自行车最少的路径。

    易错点

    🍠因为可能存在多条最短路径,所以某个站点的前一个最短路径站点可能有多个,在记录时用vector存储。在DFS中,需要计算每一条最短路径的send和back情况,一条从源点到问题站点的路径计算完成后,tempPath返回到上一次路径分叉的地方,从下一条路径继续计算。这里的递归思想很值得思考~~(*^▽^*)~~

    🍠输出的时候记得倒序输出。

    代码

    1. #include
    2. #include
    3. #include
    4. using namespace std;
    5. const int inf = 0x3f3f3f;
    6. int Cmax,N,Sp,M; //Cmax:站点最大容量 N:站点数 Sp:问题站点 M:道路数
    7. int Ci[510],T[510][510]; //每个站点自行车数量,站点间时间
    8. int vis[510],dis[510];
    9. vector<int> pre[510],path,tempPath;
    10. int minSend=inf,minBack=inf;
    11. //**标准最短路径算法**
    12. void Dijkstra(int s){
    13. fill(dis,dis+N,inf);
    14. dis[s] = 0;
    15. while(1){
    16. int index = -1;
    17. int min_dis = inf;
    18. for(int i=0;i
    19. if(!vis[i] && dis[i] < min_dis){
    20. index = i;
    21. min_dis = dis[i];
    22. }
    23. }
    24. if(index == -1) return;
    25. vis[index] = 1;
    26. for(int i=0;i
    27. if(!vis[i] && T[index][i]){
    28. if(dis[index]+T[index][i]
    29. dis[i] = dis[index]+T[index][i];
    30. pre[i].clear();
    31. pre[i].push_back(index);
    32. }else if(dis[index]+T[index][i]==dis[i]){
    33. pre[i].push_back(index);
    34. }
    35. }
    36. }
    37. }
    38. }
    39. void DFS(int s){
    40. tempPath.push_back(s); //从问题节点倒着插入到源点
    41. //递归到源点
    42. if(s==0){
    43. int send=0,back=0;
    44. for(int i=tempPath.size()-1;i>-1;i--){
    45. //如果节点自行车数多了,则带走
    46. if(Ci[tempPath[i]]>0) back += Ci[tempPath[i]];
    47. //如果少了
    48. else{
    49. //先由从其他站点带走的补充
    50. if(back>-Ci[tempPath[i]]) back += Ci[tempPath[i]];
    51. //不够的话则增加源点带出的自行车
    52. else{
    53. send += -Ci[tempPath[i]]-back;
    54. back = 0;
    55. }
    56. }
    57. }
    58. if(send
    59. minSend = send;
    60. minBack = back;
    61. path = tempPath;
    62. }else if(send==minSend && back
    63. minBack = back;
    64. path = tempPath;
    65. }
    66. tempPath.pop_back();
    67. return;
    68. }
    69. for(int i=0;isize();i++){
    70. DFS(pre[s][i]);
    71. }
    72. //没有多条路径则回退
    73. tempPath.pop_back();
    74. }
    75. int main(){
    76. cin >> Cmax >> N >> Sp >> M;
    77. N++; //加上源点
    78. int Si,Sj;
    79. fill(T[0],T[0]+N*N,0);
    80. for(int i=1;i
    81. cin >> Ci[i];
    82. Ci[i] -= Cmax/2; //大于0的话需要带走,小于0需要补充
    83. }
    84. for(int i=0;i
    85. cin >> Si >> Sj;
    86. cin >> T[Si][Sj];
    87. T[Sj][Si] = T[Si][Sj];
    88. }
    89. Dijkstra(0); //PBMC位于源点
    90. DFS(Sp);
    91. cout << minSend << " ";
    92. cout << path[path.size()-1];
    93. for(int i=path.size()-2;i>=0;i--)
    94. {
    95. cout << "->" << path[i];
    96. }
    97. cout << " " << minBack << endl;
    98. return 0;
    99. }

    🧡1030 Travel Plan

    题目链接:PTA | 程序设计类实验辅助教学平台

    解析

    💌相对来说这道题就简单多啦,同样是找最短路径,如果有多条,选择花费最少的那一条。为什么这道题不需要找出所有的路径之后再计算呢?因为花费肯定是越来越多的,只需要从当前状态判断就可以了,而上一道题我们不知道后面的站点自行车是多了还是少了。

    易错点

    🍠经过上道题的洗礼这道题轻而易举啦~~

    代码

    1. #include
    2. using namespace std;
    3. int N,M,S,D;
    4. int mp[510][510],dis[510],vis[510];
    5. int money[510][510],cost[510];
    6. int pre[510];
    7. vector<int>path; //不固定长度,可以调用函数
    8. const int inf = 0x3f3f3f;
    9. void DFS(int d)
    10. {
    11. if(d == S)
    12. {
    13. path.push_back(d); //从起始点开始push
    14. return;
    15. }
    16. DFS(pre[d]); //从后往前递归
    17. path.push_back(d); //一直push到终点
    18. }
    19. void Dijkstra(int s)
    20. {
    21. fill(dis,dis+N,inf);
    22. dis[s] = 0;
    23. cost[s] = 0;
    24. while(1)
    25. {
    26. int index = -1;
    27. int min_dis = inf;
    28. //遍历所有没有访问过的节点,找出距离源点s最近的节点index
    29. for(int i=0; i
    30. {
    31. if(!vis[i] && dis[i] < min_dis)
    32. {
    33. index = i;
    34. min_dis = dis[i];
    35. }
    36. }
    37. if(index == -1) return;
    38. vis[index] = 1;
    39. //遍历所有与index相邻的节点,更新dis
    40. for(int i=0; i
    41. {
    42. if(!vis[i] && mp[index][i]) //存在路径
    43. {
    44. if(dis[index] + mp[index][i] < dis[i])
    45. {
    46. dis[i] = dis[index] + mp[index][i];
    47. cost[i] = cost[index] + money[index][i];
    48. pre[i] = index; //总路程最短的前驱顶点
    49. }
    50. else if(dis[index] + mp[index][i] == dis[i])
    51. {
    52. if(cost[index] + money[index][i] < cost[i])
    53. {
    54. cost[i] = cost[index] + money[index][i];
    55. pre[i] = index;
    56. }
    57. }
    58. }
    59. }
    60. }
    61. }
    62. int main(){
    63. cin >> N >> M >> S >> D;
    64. for(int i=0; i
    65. {
    66. int start,end,far,much;
    67. cin >> start >> end >> far >> much;
    68. mp[start][end] = mp[end][start] = far; //距离
    69. money[start][end] = money[end][start] = much; //花费
    70. }
    71. Dijkstra(S);
    72. DFS(D);
    73. for(int i=0; isize(); i++)
    74. {
    75. cout << path[i] << " ";
    76. }
    77. cout << dis[D] << " " << cost[D] << endl;
    78. }
  • 相关阅读:
    使用tftpd更新开发板内核
    服务器存储面临的两大难题
    k8s配置StatefulSet解读
    C# 参数名加冒号,可以打乱参数顺序
    迅为LS2K0500开发板动态电源管理龙芯自主指令架构
    工作常用之Spark调优一】
    【PHP】手术麻醉系统源码
    力扣每日一题 猜数字游戏 阅读理解
    uniapp -- 扫码记录(针对app场景)
    容器云安全挑战和攻防应对
  • 原文地址:https://blog.csdn.net/qq_41847894/article/details/127732187