POJ 3255(dijkstra优化,次最短路)

题意:求 1 - n 的次最短路

分析:

  先来谈谈Dijkstra的优化。对于每次寻找到当前为访问过的点中距离最短的那一个,运用优先队列进行优化,避免全部扫描,每更新一个点的最短距离就加入优先队列。有人会问,一个点如果已经处理完成了,那它还留在队列中怎么办?我们放入队列时将一个点那时的顶点编号和最短距离进行打包,如果取出该点时,它当前的最短距离小于该点标记的最短距离,说明该点已经取到最短距离,不进行操作。或者直接用一个vis数组来记录某一个点是否已经取到最短距离;其次的优化是用邻接表存储与每一个点相连的所有边,方便处理。

  这道题的做法和最短路径基本一致,唯一的不同点在于,在求出最短路径的情况下必须要保留下次短路径。对于Dijkstra判断中取出的每一个点,如果到它的最短距离大于当前该点的次短距离,则当前该点已经取到最短距离和次短距离,不进行操作,否则进行两次判断:如果小于最短边,则赋给最短边

#include <iostream>
#include <cstring>
#include <string>
#include <algorithm>
#include <queue>
#include <stack>
#include <stdio.h>
#include <cmath>
#include <string.h>
#include <vector>

#define ll long long
using namespace std;

const int inf = 0x3f3f3f3f;
ll d[5050], d2[5050];
struct edge{
    int u, v, w, next;
}e[200100];
int head[5050], visit[5050], cnt, n, r;
struct node
{
    int id;
    ll dist;
    node(int _id = 0, ll _dist = 0) : id(_id), dist(_dist){}
    bool operator < (const node & x) const
    {
        return dist > x.dist;
    }
};

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

void dij()
{
    for(int i = 0; i <= n; i++)
        d[i] = d2[i] = inf;
    priority_queue<node> q;
    while(!q.empty())
        q.pop();
    d[1] = 0;
    q.push(node(1, 0));
    node p;
    while(!q.empty())
    {
        p = q.top();
        q.pop();
        int u = p.id;
        ll dis = p.dist;
        if(d2[u] < dis)
            continue;
        for(int i = head[u]; i != -1; i = e[i].next)
        {
            int v = e[i].v;
            ll dd = dis + e[i].w;
            if(d[v] > dd)
            {
                swap(d[v], dd);
                q.push(node(v, d[v]));
            }
            if(d2[v] > dd && dd > d[v])
            {
                d2[v] = dd;
                q.push(node(v, d2[v]));
            }
        }
    }
}

int main()
{
    ios::sync_with_stdio(false);
    int u, v, w;
    cnt = 0;
    memset(head, -1, sizeof(head));
    scanf("%d%d", &n, &r);
    for(int i = 0; i < r; i++)
    {
        scanf("%d%d%d", &u, &v, &w);
        add(u, v, w);
        add(v, u, w);       
    }
    dij();
    printf("%lld\n", d2[n]);
    return 0;
}

  

,并将最短边赋给次短边;或者如果大于最短变且小于次短边,则赋给次短边。两次完成之后均要加入队列

猜你喜欢

转载自www.cnblogs.com/zxybdnb/p/11576109.html