如何用求次长边——POJ 3255 题解

题目大意

给你一个 \(n\) 个点,\(m\) 条边的无向图,求出这个无向图中从1到n的次短路。其中\(n \le 5000\),\(m \le 100000\)。

题目传送门

POJ 3255

思路

其实求次长路是很简单的一个问题,但是网上却有很多算法都过于复杂了。首先我们先求出从1到每个结点的最短路长度(用Dijkstra或者是SPFA都可以),存入数组 \(dis1\) 中,然后再求出从结点 \(n\) 到任意结点的最短路的长度,存入数组 \(dis2\) 中。
然后我们枚举这个图中的所有边 \((u, v)\) 然后我们设 \(D = dis1[u] + w(u,v) + dis2[v]\)(\(w(u,v)\)为 \(u\) 到 \(v\) 的长度)。 然后我们判断一下假如 \(D\) 的值不等于从 \(1\) 到 \(n\) 的最短路长度,就用这个 \(D\) 去更新答案。

理由

因为次短路中一定至少有一条边与最短路中不一样,所以我们可以枚举一条边,强制从 \(1\) 到 \(n\) 的时候一定要经过这条边,然后再用这样的最短路去更新答案。有的时候枚举的这条边恰好在最短路上(最短路不只一条),那么我们如何判断呢?假如枚举到边 \((u,v)\) 那么假如 \(dis1[u] + w(u,v) + dis2[v] = dis1[n]\),就说明这条边在最短路上。然后假如这个边不在最短路上,那么一定要通过这个边从 \(1\) 到达 \(n\) 的最短路的长度就是 \(dis1[u] + w(u,v) + dis2[v]\),然后我们用这个东西去更新答案,那么得到的一定至少一条边不在最短路上的最短路,因为一个图中除了最短路,其余的路都不比最短路长,所以我们这样找到的一定是除了最短路以外的最短的边,即次短路。

代码

#include <iostream>
#include <cstdio>
#include <queue>
#include <cstring>
#include <algorithm>

using namespace std;

const int N = 5e3 + 5;
const int M = 2e5 + 5;

int n, m;
int u, v, w;
int cnt = 0;
int head[N];
int dis1[N];
int dis2[N];

struct EDGE {
    int s;
    int e;
    int w;
    int nxt;
} Edge[M];

void add(int u, int v, int w) {
    ++cnt;
    Edge[cnt].s = u;
    Edge[cnt].e = v;
    Edge[cnt].w = w;
    Edge[cnt].nxt = head[u];
    head[u] = cnt;
}

int read() {
    int s = 0, w = 1;
    char ch = getchar();
    while (ch < '0' || ch > '9') {
        if (ch == '-') w = -1;
        ch = getchar();
    }
    while (ch >= '0' && ch <='9') {
        s = s * 10 + ch - '0';
        ch = getchar();
    }
    return s * w;
}

void write(int x) {
    if (x < 0) putchar('-'), x = -x;
    if (x > 9) write(x / 10);
    putchar(x % 10 + '0');
}

void Spfa1(int x) {
    queue<int> q;
    q.push(x);
    memset(dis1, 0x3f, sizeof(dis1)); //初始化dis1
    dis1[x] = 0;
    while (!q.empty()) {
        int now = q.front(); q.pop();
        for (register int i = head[now]; i; i = Edge[i].nxt) {
            if (dis1[Edge[i].e] > dis1[now] + Edge[i].w) {
                dis1[Edge[i].e] = dis1[now] + Edge[i].w;
                q.push(Edge[i].e);
            }
        }
    }
}

void Spfa2(int x) {
    queue<int> q;
    q.push(x);
    memset(dis2, 0x3f, sizeof(dis2)); //初始化dis1
    dis2[x] = 0;
    while (!q.empty()) {
        int now = q.front(); q.pop();
        for (register int i = head[now]; i; i = Edge[i].nxt) {
            if (dis2[Edge[i].e] > dis2[now] + Edge[i].w) {
                dis2[Edge[i].e] = dis2[now] + Edge[i].w;
                q.push(Edge[i].e);
            }
        }
    }
}

int main(int argc, char const *argv[]) {
    n = read(), m = read();
    for (register int i = 1; i <= m; ++i) {
        u = read(), v = read(), w = read();
        add(u, v, w);
        add(v, u, w); //添加双向边
    }
    Spfa1(1);
    Spfa2(n);
    int ans = 0x3f3f3f3f;
    for (register int i = 1; i <= cnt; ++i) {
        int dis_tmp = dis1[Edge[i].s] + Edge[i].w + dis2[Edge[i].e];
        if (dis_tmp != dis1[n] && dis_tmp < ans) ans = dis_tmp;
    }
    write(ans);
    return 0;
}

原文地址:https://www.cnblogs.com/lixiao189/p/9853486.html

时间: 2024-08-01 05:48:44

如何用求次长边——POJ 3255 题解的相关文章

POJ 3255 &amp;&amp; HDU 1688 &amp;&amp; HDU 3191 次短路问题

POJ 3255 Roadblocks Time Limit: 2000MS   Memory Limit: 65536K Total Submissions: 7627   Accepted: 2798 Description Bessie 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 h

POJ 3255 Roadblocks (次短路问题)

解法有很多奇葩的地方,比如可以到达终点再跳回去再跳回来(比如有两个点)....反正就是不能有最短路,不过没关系,算法都能给出正确结果 思想:和求最短路上的点套路一样,spfa先正着求一次,再反着求一次最短路,然后枚举每条边<i,j>找dist_zheng[i] + len<i,j> + dist_fan[j]的第二小值即可!注意不能用邻接矩阵,那样会MLE,应该用邻接表 /* poj 3255 3808K 266MS */ #include<cstdio> #inclu

poj 3255 Roadblocks【次短路】

题目:poj 3255 Roadblocks 题意:给出一个无向图,然后求1到n点的次短路 分析:两种做法,第一种,Astat+最短路求k短路的方法. 第二种是比较暴力的方法. 先求1点到所有点的最短路dis1 然后求n点到所有点的最短路dis2 然后枚举所有边,则次短路为dis1[from] + dis2[to] + w[i]中大于最短路的最短的. AC代码: #include <cstdio> #include <string> #include <cstring>

[求PN点] poj 2505 A multiplication game

题目链接: http://poj.org/problem?id=2505 A multiplication game Time Limit: 1000MS   Memory Limit: 65536K Total Submissions: 5098   Accepted: 2573 Description Stan and Ollie play the game of multiplication by multiplying an integer p by one of the numbers

POJ - 3255 Roadblocks (次短路)

POJ - 3255 Roadblocks Time Limit: 2000MS Memory Limit: 65536KB 64bit IO Format: %I64d & %I64u Submit Status Description Bessie 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

POJ 3255 Roadblocks (Dijkstra求最短路径的变形)(Dijkstra求次短路径)

Roadblocks Time Limit: 2000MS   Memory Limit: 65536K Total Submissions: 16425   Accepted: 5797 Description Bessie 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

POJ 3255 Roadblocks (次短路模板)

Roadblocks http://poj.org/problem?id=3255 Time Limit: 2000MS   Memory Limit: 65536K       Description Bessie 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 quick

【EXT-BSGS算法求离散对数】POJ Clever Y 3243

Clever Y Time Limit: 5000MS Memory Limit: 65536K Total Submissions: 7259 Accepted: 1795 Description Little Y finds there is a very interesting formula in mathematics: XY mod Z = K Given X, Y, Z, we all know how to figure out K fast. However, given X,

poj 1066 题解

题意:求从正方体外面到达这个黑点所需穿过的最少线段数(规定只能从线段中点穿过,包括最外层的墙),共有n面墙 0 <= n <= 30 题解:事实上枚举边界上的中点,判断它和黑点的线段与这些墙的交点数即可 解释:注意到,墙这一长线段相对于黑点连线,等价于直线--无论是在实现上还是题意上.连线若与墙相交,则黑点与枚举点必在墙两侧,无可避免地要穿过这面墙,至于从线段中点穿过在本题中是没有意义的.起始点选取本该在线段中点,但显然选取两个端点的最小值不会比它差,而一个端点的结果不会比相邻的两个中点结果好