1. 程式人生 > >【演算法練習】洛谷P1608 路徑統計(SPFA最短路計數)

【演算法練習】洛谷P1608 路徑統計(SPFA最短路計數)

題意

求最短路徑的數目,可能用重邊。

題解

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; }