【演算法練習】洛谷P1608 路徑統計(SPFA最短路計數)
阿新 • • 發佈:2019-01-06
題意
求最短路徑的數目,可能用重邊。
題解
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;
}