题意:
- 求从起点到终点的次短路
Bellman-Ford算法:
- 把有向图的边存起来,然后每次扫描所有边,来更新起点到每个点的最短路,当这一次扫描,一次更新都没有的时候,说明所有顶点的最短路已经求得。复杂度是 O(|E|∗|V|) 。根据这个思想还可以来判断图中存不存在负圈。
Dijkstra算法(戴克斯特拉):
- 1.初始所有顶点都是未使用过,且除了起点最短距离为0外,所有顶点最短距离都为INF。
- 2.找出所有未使用顶点中,最短距离最小的点,由它更新出所有和它相连顶点的最短路。
3.重复2步骤,直到所有顶点都被使用过。
这种方法的实现复杂度是 O(|V|2) ,还可以优化。如果用一个优先队列把所有未使用过且最短距离(还不一定是最终最短距离)已知的顶点存起来,每次取队列底部的那个元素扩展,并将扩展得到的元素全部插入优先队列,这样删除插入的效率都是 O(log|V|) ,整个算法的效率就是 O(|E|log|V|)
我的思路:
- 先求出到所有顶点的最短路。然后次短路无非是由最短路加上一条边,或最短路加上一条边得来,据此法则求次短路。要注意可以先到终点然后回去,再到终点。比如只有两个顶点,一个边的图,次短路是三倍边长。我的方法中,更新次短路用到的是Bellman-Ford算法的思想。
书上的思路:
- 书上用的Dijstra算法实现,用dist[v]记录最短路,dist2[v]记录次短路,这样每次都按照规则更新最短路和次短路即可。
心得:
- 学习算法的时候不要想着记忆具体实现,而是只关注抽象思维部分,具体实现由抽象思维得出即可
#include <set>
#include <map>
#include <cmath>
#include <stack>
#include <queue>
#include <string>
#include <vector>
#include <cstdio>
#include <cstring>
#include <iostream>
#include <algorithm>
using namespace std;
typedef long long int LL;
const int M = 10009,INF = 0x3fffffff;
int v, e;
struct edge { int from, to, cost; }E[300009];
pair<int, int> d[M];
void input(void) {
for (int i = 0; i < e / 2; i++) {
scanf("%d%d%d", &E[i].from, &E[i].to, &E[i].cost);
E[i].from--;
E[i].to--;
E[e / 2 + i].from = E[i].to;
E[e / 2 + i].to = E[i].from;
E[e / 2 + i].cost = E[i].cost;
}
}
int second_shortest_path(void) {
for (int i = 0; i < v; i++) { d[i].first = d[i].second = INF; }
d[0].first = 0;
edge temp;
while (true) {
bool update = false;
for (int i = 0; i < e; i++) {
temp = E[i];
if (d[temp.from].first != INF && d[temp.to].first > d[temp.from].first + temp.cost) {
d[temp.to].first = d[temp.from].first + temp.cost;
update = true;
}
}
if (!update) break;
}
while (true) {
bool update = false;
for (int i = 0; i < e; i++) {
temp = E[i];
//if (temp.from == v - 1) continue;
if (d[temp.from].first != INF) {
if (d[temp.to].second > d[temp.from].second + temp.cost && d[temp.from].second + temp.cost > d[temp.to].first) {
d[temp.to].second = d[temp.from].second + temp.cost;
update = true;
}
if (d[temp.to].second > d[temp.from].first + temp.cost && d[temp.from].first + temp.cost > d[temp.to].first) {
d[temp.to].second = d[temp.from].first + temp.cost;
update = true;
}
}
}
//cout << d[ v -1].first << endl;
if (!update && d[v - 1].second != INF) break;
}
return d[v - 1].second;
}
int main(void) {
//problem: , address:
while (~scanf("%d%d", &v, &e)) {
e = e * 2;
input();
printf("%d\n", second_shortest_path());
}
return 0;
}