POJ - 3255 Roadblocks 【次短路】

版权声明:如需转载,记得标识出处 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;
}

猜你喜欢

转载自blog.csdn.net/godleaf/article/details/87894774