洛谷P2384 最短路,积化加
题意:给定 n 个点的带权有向图,求从 1 到 n 的路径中边权之积最小,最终答案对9987取模。
进行最短路松弛时,取对数,积化加,存一下前驱点和原边长即可
#include <cstdio>
#include <cmath>
#include <iostream>
#include <queue>
#include <algorithm>
#include <string.h>
using namespace std;
const int mo = 9987;
const int N = 1010;
const int M = 1000010;
int n, m, l = 0;
int last[N] = {0}, r[N][2];
double dis[N];
bool vis[N] = {false};
int pre[M], len[M], other[M];
struct rec {
int x;
double dis;
bool operator < (const rec &a) const {
return(a.dis < dis);
}
};
inline void read(int &x) {
x = 0; bool flag = false; char ch;
while (ch = getchar(), ch < '!');
if (ch == '-') flag = true, ch = getchar();
while (x = x * 10 + ch - '0', ch = getchar(), ch > '!');
if (flag) x = -x;
}
void connect(int x, int y, int z) {
l++;
pre[l] = last[x];
last[x] = l;
other[l] = y;
len[l] = z;
}
void dijkstra() {
priority_queue<rec> que;
for (int i = 1; i <= n; i++) dis[i] = 0x3f3f3f3f;
dis[1] = 0;
que.push(rec{1, 0});
//
while (!que.empty()) {
rec cur = que.top();
que.pop();
if (vis[cur.x]) continue;
vis[cur.x] = true;
//
int p, q;
q = last[cur.x];
while (q) {
p = other[q];
if (dis[p] > dis[cur.x] + log(len[q])) {
dis[p] = dis[cur.x] + log(len[q]);
que.push(rec{p, dis[p]});
r[p][0] = cur.x;
r[p][1] = len[q];
}
q = pre[q];
}
}
}
int main() {
read(n); read(m);
for (int i = 1; i <= m; i++) {
int x, y, z;
read(x); read(y); read(z);
connect(x, y, z);
}
dijkstra();
int cur = n;
int ans = 1;
while (cur != 1) {
ans = (ans * r[cur][1]) % mo;
cur = r[cur][0];
}
printf("%d\n", ans);
return 0;
}