问题描述

X城有一个含有N个节点的通信网络,在通信中,我们往往关心信息从一个节点I传输到节点J的最短路径。遗憾的是,由于种种原因,线路中总有一些节点会出故障,因此在传输中要避开故障节点。

任务一:在己知故障节点的情况下,求避开这些故障节点,从节点I到节点J的最短路径S0。

任务二:在不考虑故障节点的情况下,求从节点I到节点J的最短路径S1、第二最短路径S2。

输入文件

第1行: N I J (节点个数 起始节点 目标节点)

第2—N+1行: Sk1 Sk2…SkN (节点K到节点J的距离为SkJ K=1,2,……,N)

最后一行: P T1 T2……Tp (故障节点的个数及编号)

输出文件

S0 S1 S2 (S1<=S2 从节点I到节点J至少有两条不同路径)

样例输入

5 1 5

0 10 5 0 0

10 0 0 6 20

5 0 0 30 35

0 6 30 0 6

0 20 35 6 0

1 2

样例输出

40 22 30

约束条件

(1)N<=50 N个节点的编号为1,2,…,N

(2)Skj为整数,Skj<=100,(K,J=1,2…,N 若Skj=0表示节点K到节点J没线路)

(3)P<=5  

思路:

首先简单的说一下次短路经:

次短路径可以看作是k短路径问题的一种特殊情况,求k短路径有Yen算法等较为复杂的方法,对于次短路径,可以有更为简易的方法。下面介绍一种求两个顶点之间次短路径的解法。

我们要对一个有向赋权图(无向图每条边可以看作两条相反的有向边)的顶点S到T之间求次短路径,首先应求出S的单源最短路径。遍历有向图,标记出可以在最短路径上的边,加入集合K。然后枚举删除集合K中每条边,求从S到T的最短路径,记录每次求出的路径长度值,其最小值就是次短路径的长度。

在这里我们以为次短路径长度可以等于最短路径长度,如果想等,也可以看作是从S到T有不止一条最短路径。如果我们规定求从S到T大于最短路径长度的次短路径,则答案就是每次删边后大于原最短路径的S到T的最短路径长度的最小值。

用Dijkstra+堆求单源最短路径,则每次求最短路径时间复杂度为O(Nlog(N+M) + M),所以总的时间复杂度为O(NM*log(N+M) + M^2)。该估计是较为悲观的,因为一般来说,在最短路径上的边的条数要远远小于M,所以实际效果要比预想的好。

对于前面两个询问,直接spfa即可(同时记录最短路径),对于第三个询问,每一次删掉最短路径中的一条边,然后再spfa找到删过边后的最短路,即为次短路。

代码:

  1. #include<stdio.h>
  2. #include<iostream>
  3. #include<queue>
  4. #include<string.h>
  5. const int INF=0x3f3f3f3f;
  6. using namespace std;
  7. int n,st,ed,cnt,st1,ed1;
  8. struct Node
  9. {
  10. int to,val;
  11. int Next;
  12. }node[2600];
  13. int head[55];//头结点
  14. int pro[55];//有问题的点
  15. int pre[55];//前去节点
  16. int dis[55];//距离
  17. int vis[55];//标记有没有访问过
  18. void init()
  19. {
  20. for(int i=0;i<=n;i++)
  21. head[i]=-1;
  22. }
  23. void add(int a,int b,int w)
  24. {
  25. node[cnt].to=b;
  26. node[cnt].val=w;
  27. node[cnt].Next=head[a];
  28. head[a]=cnt;
  29. cnt++;
  30. }
  31. void spfa(int flag)
  32. {
  33. if(flag==1)
  34. memset(pre,0,sizeof(pre));
  35. queue<int>q;
  36. for(int i=1;i<=n;i++)
  37. {
  38. dis[i]=INF;
  39. vis[i]=0;
  40. }
  41. dis[st]=0;
  42. vis[st]=1;
  43. pre[st]=-1;
  44. q.push(st);
  45. while(!q.empty())
  46. {
  47. int x=q.front();
  48. q.pop();
  49. vis[x]=0;
  50. for(int i=head[x];i!=-1;i=node[i].Next)
  51. {
  52. int y=node[i].to;
  53. if ((x == st1 && y == ed1) || (x == ed1 && y == st1)) continue;
  54. if(pro[y]==1) continue;//第一次找最短路的时候遇见故障点要跳过
  55. if(dis[y]>dis[x]+node[i].val)
  56. {
  57. dis[y]=dis[x]+node[i].val;
  58. if(flag==1) pre[y]=x;
  59. if(vis[y]==0)
  60. {
  61. vis[y]=1;
  62. q.push(y);
  63. }
  64. }
  65. }
  66. }
  67. }
  68. int main()
  69. {
  70. while(scanf("%d%d%d",&n,&st,&ed))
  71. {
  72. init();
  73. cnt=0;
  74. int w,num;
  75. for(int i=1; i<=n; i++)
  76. for(int j=1; j<=n; j++)
  77. {
  78. scanf("%d",&w);
  79. if(w!=0)
  80. {
  81. add(i,j,w);//按照头插法保存下图的信息
  82. }
  83. }
  84. scanf("%d",&w);
  85. for(int i=1;i<=w;i++)//将有问题的点标记下来
  86. {
  87. scanf("%d",&num);
  88. pro[num]=1;
  89. }
  90. //去掉有故障的点寻找最短路
  91. spfa(1);
  92. printf("%d ",dis[ed]);
  93. //不考虑有故障的点寻找最短路
  94. memset(pro,0,sizeof(pro));
  95. spfa(1);
  96. printf("%d ",dis[ed]);
  97. //求次短路是在不考虑有故障的点的基础的
  98. int Min=INF;
  99. int v ;
  100. v=ed;//倒着一条边一条边的删除
  101. while(pre[v]!= -1)
  102. {
  103. st1=pre[v];//删除的这条边的起始点
  104. ed1=v;//删除的这条边的终点
  105. spfa(0);
  106. Min=min(Min,dis[ed]);//然后在这些最短路里面找一条最小的
  107. v=pre[v];
  108. }
  109. printf("%d\n",Min);
  110. }
  111. return 0;
  112. }

HAOI 2005 路由选择问题 (最短路+次短路)的更多相关文章

  1. 算法笔记--次小生成树 && 次短路 && k 短路

    1.次小生成树 非严格次小生成树:边权和小于等于最小生成树的边权和 严格次小生成树:    边权和小于最小生成树的边权和 算法:先建好最小生成树,然后对于每条不在最小生成树上的边(u,v,w)如果我们 ...

  2. CSU 2005 Nearest Maintenance Point(最短路+bitset)

    https://vjudge.net/problem/CSU-2005 题意:给出带权值的图,图上有一些特殊点,现在给出q个询问,对于每个询问,输出离该点最近的特殊点,如果有多个,则按升序输出. 思路 ...

  3. php短路与 短路或

    关于php短路的问题特性,三种写法的区别 $a = 1;$b=0;第一种: $a && $b = 'cccccccc';第二种 $a || $b = 'cccccccc';第三种 if ...

  4. hdu 2544最短路——最短路的初次总结 UESTC 6th Programming Contest Online

    这是一道标准的模板题,所以拿来作为这一段时间学习最短路的总结题目. 题意很简单: 有多组输入数据,每组的第一行为两个整数n, m.表示共有n个节点,m条边. 接下来有m行,每行三个整数a, b, c. ...

  5. BZOJ 1726: [Usaco2006 Nov]Roadblocks第二短路( 最短路 )

    从起点和终点各跑一次最短路 , 然后枚举每一条边 , 更新answer ---------------------------------------------------------------- ...

  6. HDU2544-最短路(最短路模版题目)

    Problem Description 在每年的校赛里,所有进入决赛的同学都会获得一件很漂亮的t-shirt.但是每当我们的工作人员把上百件的衣服从商店运回到赛场的时候,却是非常累的!所以现在他们想要 ...

  7. 最短路 次短路 k短路(k很小)

    最短路 luogu 3371 https://www.luogu.org/problemnew/show/P3371 #include <cstdio> #include <cstd ...

  8. LOJ#6354. 「CodePlus 2018 4 月赛」最短路[最短路优化建图]

    题意 一个 \(n\) 个点的完全图,两点之间的边权为 \((i\ xor\ j)*C\) ,同时有 \(m\) 条额外单向路径,问从 \(S\) 到 \(T\) 的最短路. \(n\leq 10^5 ...

  9. BZOJ1726: [Usaco2006 Nov]Roadblocks第二短路 K短路

    Description 贝茜把家搬到了一个小农场,但她常常回到FJ的农场去拜访她的朋友.贝茜很喜欢路边的风景,不想那么快地结束她的旅途,于是她每次回农场,都会选择第二短的路径,而不象我们所习惯的那样, ...

随机推荐

  1. 小程序 上啦下拉刷新window配置

    "enablePullDownRefresh": "true"   /** * 页面相关事件处理函数--监听用户下拉动作 */ onPullDownRefres ...

  2. Qt托盘程序

    使用QSystemTrayIcon类可以实现托盘程序.在这里使用QMainWindow做实例: mainwindow.h头文件 #ifndef MAINWINDOW_H #define MAINWIN ...

  3. java 连接mysql增删改查

    1.创建mysql测试表 2.按下图创建3个文件夹与3个类 3.三个类的代码 PersionDao :目录(Data Access Object), 数据访问对象是第一个面向对象的数据库接口 pack ...

  4. MT【138】对称乎?

    已知\(a+b=1\),求\((a^3+1)(b^3+1)\)的最大值______ : 解答: \[ \begin{align*} (a^3+1)(b^3+1) &=a^3+b^3+a^3+b ...

  5. 【刷题】BZOJ 1070 [SCOI2007]修车

    Description 同一时刻有N位车主带着他们的爱车来到了汽车维修中心.维修中心共有M位技术人员,不同的技术人员对不同的车进行维修所用的时间是不同的.现在需要安排这M位技术人员所维修的车及顺序,使 ...

  6. CF960G Bandit Blues 【第一类斯特林数 + 分治NTT】

    题目链接 CF960G 题解 同FJOI2016只不过数据范围变大了 考虑如何预处理第一类斯特林数 性质 \[x^{\overline{n}} = \sum\limits_{i = 0}^{n}\be ...

  7. 洛谷 P4091 [HEOI2016/TJOI2016]求和 解题报告

    P4091 [HEOI2016/TJOI2016]求和 题目描述 在2016年,佳媛姐姐刚刚学习了第二类斯特林数,非常开心. 现在他想计算这样一个函数的值: \[ f(n)=\sum_{i=0}^n\ ...

  8. 【poj2127】 Greatest Common Increasing Subsequence

    http://poj.org/problem?id=2127 (题目链接) 题意 计算两个序列$a$和&b$的最长公共上升子序列. Solution 爸爸的$n^3$算法莫名其妙RE了,不爽之 ...

  9. 音视频处理之FFmpeg+SDL视频播放器20180409

    一.FFmpeg视频解码器 1.视频解码知识 1).纯净的视频解码流程 压缩编码数据->像素数据. 例如解码H.264,就是“H.264码流->YUV”. 2).一般的视频解码流程 视频码 ...

  10. python学习笔记__反射

    反射 # 通过字符串的形式对对象中的成员进行操作(获取/查找/添加/删除). 操作的内置函数: 1.获取   getattr(object, name) # 去对象object中获取name的内容 c ...