洛谷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
", ans);
	return 0;
}
原文地址:https://www.cnblogs.com/Eirlys/p/13495853.html