一道神奇的最短路题(对数的用法)

给出一张无向带权图,找一条从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;
} 

 

posted @ 2021-09-15 17:33  T_X蒻  阅读(59)  评论(0编辑  收藏  举报