原题地址
https://www.patest.cn/contests/pat-a-practise/1003
题意:给定N个城市以及M条城市之间的道路,每座城市有自己的权重city[i],每条道路也有自己的权重cost[i][j],求源顶点v0到目标顶点vt的最短路径的数量,以及沿着最短路径的累加顶点权重的最大值。
解题思路
本题是单源最短路径的变形题,寻找单源最短路径一般用Dijkstra算法就可以直接。
关于两种求最短路径算法的总结详见最短路径—Dijkstra算法和Floyd算法
Dijkstra算法是典型的单源最短路径算法,用于计算一个节点到其他所有节点的最短路径。
该算法把图中顶点集合V分成两组,第一组为已求出最短路径的顶点集合(用S表示,初始时S中只有一个源点,以后每求得一条最短路径 , 就将加入到集合S中,直到全部顶点都加入到S中,算法就结束了),第二组为其余未确定最短路径的顶点集合(用U表示),按最短路径长度的递增次序依次把第二组的顶点加入S中。在加入的过程中,总保持从源点v到S中各顶点的最短路径长度不大于从源点v到U中任何顶点的最短路径长度。
对于这一题来说,由于结果不关心最短路径的长度,但是关心最短路径的条数,以及这些最短路径上最大的顶点权重之和,所以一共需要维护一下变量、数组:
- visit[i]标记顶点i是否已经求得最短路径
- city数组记录每个顶点的权重,cost数组记录每条边的权重
- dist[i]记录源点 v0 到顶点 i 的最短距离.若i已经在S中,则该距离即v0到i的最短路径长度;若i不在S中,则该距离即v0只通过S中的顶点到达i的最短路径长度
- 和Prim算法的最大区别就是Prim-dist对子集S维护,而Dijkstra算法对源点v0维护。
- pathCount[j]维护源点v0到顶点j的最短路径的条数,amount[i]维护源点v0到顶点j的最短路径上的最大顶点权重之和
因此本题的关键就是在算法核心部分—松弛(Relax)时维护dist,pathCount,amount这三个数组。
- 假设 j 满足从源点v0通过S中的顶点到 j 的距离dist[j]最小,那么看能否经由 j 到S外的顶点的距离更小。若通过 j 到 k的距离 小于 v0通过之前S中的顶点到 k 的距离,则更新dist[k]的同时,更新pathCount[k]为pathCount[j],更新amount[k]为amount[j]+city[k]。
- 上面的松弛情况还是比较好理解的,但是不能遗漏另一种情况,如果这两个距离相等怎么办?那就要为pathCount[k]加上pathCount[j]这些路,同时看看amount[k]能否取得更大。
注意v0到自己时的情况,下面的代码已经对此优化。
AC代码
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
- 10
- 11
- 12
- 13
- 14
- 15
- 16
- 17
- 18
- 19
- 20
- 21
- 22
- 23
- 24
- 25
- 26
- 27
- 28
- 29
- 30
- 31
- 32
- 33
- 34
- 35
- 36
- 37
- 38
- 39
- 40
- 41
- 42
- 43
- 44
- 45
- 46
- 47
- 48
- 49
- 50
- 51
- 52
- 53
- 54
- 55
- 56
- 57
- 58
- 59
- 60
- 61
- 62
- 63
- 64
- 65
- 66
- 67
- 68
- 69
- 70
- 71
- 72
- 73
- 74
- 75
- 76
- 77
- 78
- 79
- 80
- 81
- 82
- 83
- 84
- 85
- 86
- 87
- 88
- 89
- 90
- 91
- 92
- 93
- 94
- 95
- 96
算法复杂度:O(n^2)
耗时:10 ms