版权声明:如需转载,记得标识出处 https://blog.csdn.net/godleaf/article/details/87894774
题目链接:http://poj.org/problem?id=3255
如果是求最短路,直接套模板就能AC,但是次短路怎么求。
其实仔细分析一下就能知道,如果我每一个路径都保证是最优的走法,那么得到的就是最短路径,但是如果我有一步走错了,后面又继续走最优的走法,那么得到的路径就会比最短路长,当然如果走错两步,总路径也一定比最短路径长,但是只要我走错之后又继续走最优的走法,那么走错两步的情况一定比走错一步的情况得到的路径长,所以次短路径一定在走错一步的情况里面,我们只要枚举每一条边,假设走错的是这条边,求出总路径,只取比最短路径长的最短路径就是次短路径了。
分别用两个数组存 1到任意点的最短距离,N到任意点的最短距离,假设走错的边是 (x, y) ,那么得到的路径就是 1到x的最短距离+(x, y) + N到 y的最短距离。
#include <iostream>
#include <queue>
#include <cstring>
#include <string>
#include <map>
#include <cstdio>
#include <cmath>
#include <algorithm>
#include <vector>
using namespace std;
#define lson (cur<<1)
#define rson (cur<<1|1)
typedef long long ll;
typedef pair<int, int> pii;
const int INF = 0x3f3f3f3f;
const int Maxn = 5e3+10;
const int Mod = 1e9+7;
struct Edge {
int v, cost;
} edge[100010*2];
vector <int> G[Maxn];
int d[Maxn], nd[Maxn], N, R;
bool vis[Maxn];
void spfa(int u, int *dis) {
for(int i = 1; i <= N; ++i) dis[i] = INF;
dis[u] = 0;
memset(vis, false, sizeof(vis));
vis[u] = true;
queue<int> qu;
qu.push(u);
while (!qu.empty()) {
int x = qu.front(); qu.pop();
vis[x] = false;
for(int i = 0; i < G[x].size(); ++i) {
Edge e = edge[G[x][i]];
if(dis[e.v] > dis[x]+e.cost) {
dis[e.v] = dis[x]+e.cost;
if(!vis[e.v]) {
vis[e.v] = true;
qu.push(e.v);
}
}
}
}
}
int main(void)
{
while (scanf("%d%d", &N, &R) != EOF) {
int u, v, c;
for(int i = 0; i <= N; ++i) G[i].clear();
for(int i = 0; i < R; ++i) {
scanf("%d%d%d", &u, &v, &c);
edge[i].v = v; edge[i].cost = c;
edge[i+R].v = u; edge[i+R].cost = c;
G[u].push_back(i);
G[v].push_back(i+R);
}
spfa(1, d);
spfa(N, nd);
int minx2 = INF;
for(int i = 1; i <= N; ++i) {
for(int j = 0; j < G[i].size(); ++j) {
Edge e = edge[G[i][j]];
int cost = d[i]+e.cost+nd[e.v];
if(cost == d[N]) continue;
minx2 = min(minx2, cost);
}
}
printf("%d\n", minx2);
}
return 0;
}
还有一种更直接的方法,最短路径不是每次都会做松弛操作吗,每次松弛都会把当前的距离换成更短的距离,我们只要把换掉的距离用另一个数组存起来就行了。
#include <iostream>
#include <queue>
#include <cstring>
#include <string>
#include <map>
#include <cstdio>
#include <cmath>
#include <algorithm>
#include <vector>
using namespace std;
#define lson (cur<<1)
#define rson (cur<<1|1)
typedef long long ll;
typedef pair<int, int> pii;
const int INF = 0x3f3f3f3f;
const int Maxn = 5e3+10;
const int Mod = 1e9+7;
struct Edge {
int v, cost;
} edge[100010*2];
vector <int> G[Maxn];
int d[Maxn], dt[Maxn], N, R;
bool vis[Maxn];
void spfa(int u) {
for(int i = 1; i <= N; ++i) d[i] = INF;
d[u] = 0;
memset(vis, false, sizeof(vis));
vis[u] = true;
queue<int> qu;
qu.push(u);
while (!qu.empty()) {
int x = qu.front(); qu.pop();
vis[x] = false;
for(int i = 0; i < G[x].size(); ++i) {
Edge e = edge[G[x][i]];
if(d[e.v] > d[x]+e.cost) {
dt[e.v] = d[e.v]; // 把换掉的距离存起来,可以保证的是,每次换掉的距离都比上一次的短。
d[e.v] = d[x]+e.cost;
if(!vis[e.v]) {
vis[e.v] = true;
qu.push(e.v);
}
}
}
}
}
int main(void)
{
while (scanf("%d%d", &N, &R) != EOF) {
int u, v, c;
for(int i = 0; i <= N; ++i) G[i].clear();
for(int i = 0; i < R; ++i) {
scanf("%d%d%d", &u, &v, &c);
edge[i].v = v; edge[i].cost = c;
edge[i+R].v = u; edge[i+R].cost = c;
G[u].push_back(i);
G[v].push_back(i+R);
}
spfa(1);
printf("%d\n", dt[N-1]);
}
return 0;
}