【算法练习】洛谷P1608 路径统计(SPFA最短路计数)

本文介绍使用SPFA算法解决最短路径问题,并详细解释了如何通过维护顶点访问次数来避免重复计算,确保算法效率。代码示例展示了整个过程。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

题意

求最短路径的数目,可能用重边。

题解

SPFA,为了保证不会重复计算,需要维护一个当前队列中到这些顶点的次数,每次出队时清零。

代码

// luogu-judger-enable-o2
#include<bits/stdc++.h>
using namespace std;
typedef double db;
typedef long long ll;
typedef unsigned long long ull;
const int nmax = 4e6+7;
const int INF = 0x3f3f3f3f;
const ll LINF = 0x3f3f3f3f3f3f3f3f;
const ull p = 67;
const ull MOD = 1610612741;
int n, m, tot;
int dist[nmax], cnt[nmax], head[nmax], thiscnt[nmax];
int mp[2005][2005];
int inque[nmax];
struct edge{
    int to, nxt, w;
}e[nmax<<1];
void add_edge(int u, int v, int w) {
    e[tot].to = v;
    e[tot].nxt = head[u];
    e[tot].w = w;
    head[u] = tot ++;
}
void spfa(int s) {
    for(int i = 1; i <= n; ++i) {
        dist[i] = i == s? 0 : INF;
        inque[i] = false;
    }
    queue<int> q;
    q.push(s);
    inque[s] = true;
    thiscnt[s] = cnt[s] = 1;
    while(!q.empty()) {
        int u = q.front();
        q.pop();
        inque[u] = false;
        if(u == n)
            continue;
        for(int v = 1; v <= n; ++v) {
            if(u == v || mp[u][v] == 0)
                continue;
            if(dist[v] > dist[u] + mp[u][v]) {
                dist[v] = dist[u] + mp[u][v];
                cnt[v] = thiscnt[v] = thiscnt[u];
                if(!inque[v]) {
                    inque[v] = true;
                    q.push(v);
                }
            } else if(dist[v] == dist[u] + mp[u][v]) {
                cnt[v] += thiscnt[u];
                thiscnt[v] += thiscnt[u];
                if(!inque[v]) {
                    inque[v] = true;
                    q.push(v);
                }
            }
        }
        thiscnt[u] = 0;

    }
}
//void dijkstra(int s) {
//
//}
int main() {
    scanf("%d %d",&n, &m);
    memset(head, -1, sizeof head);
    int u, v, w;
    for(int i = 1;i <= m; ++i) {
        scanf("%d %d %d", &u, &v, &w);
        if(mp[u][v] == 0)
            mp[u][v] = w;
        else
            mp[u][v] = min(mp[u][v], w);
//        add_edge(u,v,w);
//        add_edge(v,u,w);
    }
    spfa(1);
    if(dist[n] == INF) {
        printf("No answer\n");
    } else {
        printf("%d %d\n", dist[n], cnt[n]);
    }
    return 0;
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值