一道神奇的最短路题(对数的用法)
给出一张无向带权图,找一条从s到t的路径使经过的边权值乘积最小。
N,M<=1e5 weight<=1e4
直接dij的话len会达到1e4^1e5。
但是如果将边权向这样取个对数
VP = weightP1 × weightP2 × ... × weightPK
ln VP = ln weightP1 + ln weightP2 + ... + ln weightPK
就可以直接跑dij了
#include<bits/stdc++.h> using namespace std; const int MM=200005; long long n,m,u,v,ans[MM],vis[MM],to[MM],nxt[MM],head[MM],f[MM],s,t,tot,tmp,_min;; double q[MM],len[MM],w,W; void dij() { while(!vis[t]) { double tmp=100000;int _min; for(int i=1;i<=n;i++) if(!vis[i]&&len[i]<tmp) tmp=len[i],_min=i; vis[_min]=1; for(int i=head[_min];i;i=nxt[i]) if(len[_min]+q[i]<=len[to[i]]) len[to[i]]=len[_min]+q[i],f[to[i]]=_min; } } void find(int now) { ans[++tot]=now; if(now==s) return; find(f[now]); } void pp() { find(t); for(int i=tot;i>=1;i--) cout<<ans[i]<<' '; } void add(int u,int v,int w) { W=log10(w); nxt[++tot]=head[u]; head[u]=tot; to[tot]=v; q[tot]=W; } int main() { //freopen("multi.in","r",stdin); //freopen("nulti.out","w",stdout); memset(len,0x42,sizeof(len)); cin>>n>>m; for(int i=1;i<=n;i++) cin>>u>>v>>w,add(u,v,w),add(v,u,w); tot=0; cin>>s>>t; len[s]=1; dij(); pp(); return 0; }