【洛谷P2384】最短乘積路徑
阿新 • • 發佈:2018-11-03
題目大意:給定 N 個點,M 條邊的有向圖,邊有邊權,求從 1 號頂點到 N 號頂點的最短乘積路徑。(經過的路徑乘積最小)結果對9987取模。
乘積會爆 long long ,同時由於 dij 演算法的性質,又不能在 bfs 的過程中對答案取模。
同時,根據對數的性質有 \(log(x)+log(y)=log(xy)\),因此,可以採用將邊權取對數存入鄰接表中,dij 比較的時候用這個取對數之後的邊權比較,並記錄路徑,最後按照路徑還原統一處理答案。
程式碼如下
#include <bits/stdc++.h> using namespace std; const int maxv=1010; const int maxe=1e6+10; typedef pair<double,int> P; inline int read(){ int x=0,f=1;char ch; do{ch=getchar();if(ch=='-')f=-1;}while(!isdigit(ch)); do{x=x*10+ch-'0';ch=getchar();}while(isdigit(ch)); return f*x; } struct node{ int nxt,to,w; double lw; }e[maxe]; int tot=1,head[maxv]; int n,m,vis[maxv],pre[maxv][2]; double dis[maxv]; priority_queue<P> q; inline void add_edge(int from,int to,int w,double lw){ e[++tot]=node{head[from],to,w,lw},head[from]=tot; } void read_and_parse(){ n=read(),m=read(); for(int i=1,from,to,w;i<=m;i++){ from=read(),to=read(),w=read(); add_edge(from,to,w,log(w)); } } void solve(){ for(int i=1;i<=n;i++)dis[i]=0x3f3f3f3f; dis[1]=0,q.push(make_pair(0,1)); while(q.size()){ int u=q.top().second;q.pop(); if(vis[u])continue; if(u==n)break; vis[u]=1; for(int i=head[u];i;i=e[i].nxt){ int v=e[i].to,w=e[i].w; double lw=e[i].lw; if(dis[v]>dis[u]+lw){ dis[v]=dis[u]+lw; q.push(make_pair(-dis[v],v)); pre[v][0]=u,pre[v][1]=w; } } } int ans=1; for(int t=n;t!=1;t=pre[t][0]){ ans=ans*pre[t][1]%9987; } printf("%d\n",ans); } int main(){ read_and_parse(); solve(); return 0; }