AcWing 383. 观光

如果要求出最短路个数,那么就需要再拓扑图上做最短路,而能有拓扑结构的最短路模型一般只有Dijkstra和bfs两种算法。
而求次短路只需对每个点进行拆点,并且再求得最短路的同时维护一个次短路即可,每次先更新最短路,不能更新最短路再看能不能更新次短路。

代码:

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

using namespace std;

const int N = 1010, M = 100010;

struct Node 
{
    int ver, dist, type;
    bool operator> (const Node &a) const
    {
        return dist > a.dist;
    }
};

int h[N], ne[M], e[M], w[M];
int idx, n, m, S, F;
int dist[N][2], f[N][2];
bool st[N][2];

void add(int a, int b, int c) 
{
    e[idx] = b, ne[idx] = h[a], w[idx] = c, h[a] = idx ++ ;
}

int dijkstra() 
{
    memset(dist, 0x3f, sizeof dist);
    memset(f, 0, sizeof f);
    memset(st, 0, sizeof st);

    priority_queue<Node, vector<Node>, greater<Node>> heap;
    heap.push({S, 0, 0});
    dist[S][0] = 0, f[S][0] = 1;

    while (heap.size()) 
    {
        auto t = heap.top();
        heap.pop();

        int ver = t.ver, distance = t.dist, type = t.type, sum = f[ver][type];
        if (st[ver][type]) continue;
        st[ver][type] = true;

        for (int i = h[ver]; i != -1; i = ne[i]) 
        {
            int j = e[i];

            if (dist[j][0] > distance + w[i]) 
            {
                dist[j][1] = dist[j][0], f[j][1] = f[j][0]; // 如果最短路能被更新,那么当前的最短路就会变成次短路
                heap.push({j, dist[j][1], 1}); // 次短路入队
                dist[j][0] = distance + w[i], f[j][0] = sum; // 更新最短路
                heap.push({j, dist[j][0], 0}); // 最短路入队
            }
            else if (dist[j][0] == distance + w[i]) f[j][0] += sum;
            else if (dist[j][1] > distance + w[i]) // 先更新最短路,最短路不能更新再更新次短路
            {
                dist[j][1] = distance + w[i], f[j][1] = sum;
                heap.push({j, dist[j][1], 1});
            }
            else if (dist[j][1] == distance + w[i]) f[j][1] += sum;
        }
    }

    int res = f[F][0];
    if (dist[F][0] + 1 == dist[F][1]) res += f[F][1];

    return res;
}

int main() 
{
    int T;
    scanf("%d", &T);
    while (T -- ) 
    {
        scanf("%d%d", &n, &m);
        memset(h, -1, sizeof h);
        idx = 0;
        while (m -- ) 
        {
            int a, b, c;
            scanf("%d%d%d", &a, &b, &c);
            add(a, b, c);
        }

        scanf("%d%d", &S, &F);

        cout << dijkstra() << endl;
    }

    return 0;
}

 

posted @ 2021-04-14 21:38  筱翼深凉  阅读(52)  评论(0编辑  收藏  举报