DescriptionBessie has moved to a small farm and sometimes enjoys returning to visit one of her best friends. She does not want to get to her old home too quickly, because she likes the scenery along the way. She has decided to take the second-shortest rather than the shortest path. She knows there must be some second-shortest path.The countryside consists of R (1 ≤ R ≤ 100,000) bidirectional roads, each linking two of the N (1 ≤ N ≤ 5000) intersections, conveniently numbered 1…N. Bessie starts at intersection 1, and her friend (the destination) is at intersection N.The second-shortest path may share roads with any of the shortest paths, and it may backtrack i.e., use the same road or intersection more than once. The second-shortest path is the shortest path whose length is longer than the shortest path(s) (i.e., if two or more shortest paths exist, the second-shortest path is the one whose length is longer than those but no longer than any other path).InputLine 1: Two space-separated integers: N and R
Lines 2…R+1: Each line contains three space-separated integers: A, B, and D that describe a road that connects intersections A and B and has length D (1 ≤ D ≤ 5000)OutputLine 1: The length of the second shortest path between node 1 and node NSample Input4 4
1 2 100
2 4 200
2 3 250
3 4 100Sample Output450HintTwo routes: 1 -> 2 -> 4 (length 100+200=300) and 1 -> 2 -> 3 -> 4 (length 100+250+100=450)
题目大意就是在两点中找一条第二短的路线,一条路可以重复走多次。
两点间最短路肯定是用dijkstra算法,本题虽然要第二短,但只要稍加改动,便可以达到寻找第二短路径的目的。(如果dijkstra还不会建议先去学习,然后在来研究本题)。
下面进入正题,首先我们明确了用dijkstra算法做这个题,但是直接写的话,就poj的习惯来说不用多想都会超时,本题也不例外,为了避免每次都要便利一遍,我们应该使用堆维护。然后会有两个数组,一个保存最短路径,一个保存次最短路径。
废话不多说,先上代码。(代码参考文献《挑战程序设计竞赛》, 说实话它写的是什么完全看不懂,还是看了网上大神的代码才懂)。
#include <iostream>
#include <queue> //堆维护我们用优先队列
#include <cstring>
using namespace std;
typedef pair<int, int> P; //单纯的为了方便,没有多余意思, first代表距离,
//second代表顶点编号 (把两个东西让他们之间有联系)
//P.first就代表访问第一个值,P.second访问第二个值
int n, r; //题目要求输入数据
const int INF = 0x3f3f3f3f; //定义无穷大,这个就接近整形最大值了,以后别再写99999了
const int maxn = 5010;
const int maxr = 100050;
int dist[maxn]; //保存最小值
int dist2[maxr]; //保存次小值
struct edge
{
int to, cost;
edge(int tt, int cc):to(tt), cost(cc) {} //写一个构造函数,因为要用邻接表,下面就明白为什么了
};
vector<edge> G[maxr]; //邻接表
void solve()
{
//把每个顶点当前的最短距离用堆维护
//每次从堆中取出的最小值就是下一次要使用的顶点
//在每次更新时往堆里插入当前最短距离和顶点的值对
//当取出的最小值不是最短距离的话,就丢弃这个值
priority_queue<P, vector<P>, greater<P> > que; //优先队列
//这个队列自动按照升序排好,所以不需要遍历去寻找最小值了,top()就直接是最小值
memset(dist, INF, sizeof(dist));
memset(dist2, INF, sizeof(dist2));
que.push(P(0, 0));
dist[0] = 0;
while (!que.empty())
{
P p = que.top();
que.pop();
int v = p.second, d = p.first;
if (d > dist2[v]) //比第二小还要大,直接抛弃这个值
{
continue;
}
for (int i=0; i<G[v].size(); i++)
{
edge e = G[v][i];
int d2 = d + e.cost; //接着找最小值
if (d2 < dist[e.to]) //如果d2比最小值还要小,那么交换二者值
{
swap(d2, dist[e.to]);
que.push(P(dist[e.to], e.to)); //入队操作,后面取出最小值的
//时候,如果不是最短距离就丢弃这个值
}
if (d2 < dist2[e.to] && d2 > dist[e.to]) //比第二小要小,比最小值大
{
dist2[e.to] = d2;
que.push(P(dist2[e.to], e.to));
}
}
}
cout << dist2[n-1] << endl;
}
int main()
{
cin >> n >> r;
int from, to, cost;
for (int i=0; i<r; i++)
{
cin >> from >> to >> cost;
from--; //因为是邻接表,数据是从零开始的,但是题目给的数据是从1开始的,所以都减一
to--;
G[from].push_back(edge(to, cost)); //无向图,a->b 和 b->a 都得赋值
G[to].push_back(edge(from, cost)); //上面的构造函数在这里用到了,
//如果你不习惯用构造函数,可以定义一个edge temp然后在push_back(temp)
}
solve();
return 0;
}