#SPFA#洛谷 2384 最短路
题目
给定\(n\)个点的带权有向图,求从\(1\)到\(n\)的路径中边权之积最小的简单路径。
答案对9987取模
分析
此题设了陷阱,如果一边取模一边跑最短路即使最终答案最小也不一定是未取模前的最小答案
所以把乘化为\(\log\)加,记录哪些边经过,最后将这些边权相乘取模即为答案
(不过听说可能还有精度误差Err,那我就对此题束手无策了)
代码
#include <cstdio>
#include <cctype>
#include <queue>
#include <cmath>
#define rr register
using namespace std;
const int N=1011; double dis[N];
struct node{int x,y,w,next;}e[N*100];
int ls[N],n,k=1,pre[N],v[N],t,ans; queue<int>q;
inline signed iut(){
rr int ans=0; rr char c=getchar();
while (!isdigit(c)) c=getchar();
while (isdigit(c)) ans=(ans<<3)+(ans<<1)+(c^48),c=getchar();
return ans;
}
signed main(){
n=iut();
for (rr int m=iut();m;--m){
rr int x=iut(),y=iut(),w=iut();
e[++k]=(node){x,y,w,ls[x]},ls[x]=k;
}
for (rr int i=1;i<=n;++i) dis[i]=1e18;
v[1]=1,q.push(1),dis[1]=0;
while (q.size()){
rr int x=q.front(); q.pop();
for (rr int i=ls[x];i;i=e[i].next)
if (dis[e[i].y]>dis[x]+log(e[i].w)){
dis[e[i].y]=dis[x]+log(e[i].w),pre[e[i].y]=i;
if (!v[e[i].y]) v[e[i].y]=1,q.push(e[i].y);
}
v[x]=0;
}
for (ans=1,t=n;pre[t];t=e[pre[t]].x) ans=ans*e[pre[t]].w%9987;
return !printf("%d",ans);
}