最小花费(乘法最短路)

最小花费

题意

给定一个无向图,边权为 w i ( 0 ≤ w i ≤ 1 ) w_i(0\leq w_i\leq1) wi(0wi1)。定义两点之间的距离为路径上所有权值的乘积。求两点之间的最长路。

思路

假设距离为 w 1 w 2 … w k w_1w_2\dots w_k w1w2wk,可以对其取对数处理,即 log ⁡ w 1 w 2 … w k = log ⁡ w 1 + log ⁡ w 2 + … log ⁡ w k \log w_1w_2\dots w_k = \log w_1 + \log w_2 + \dots \log w_k logw1w2wk=logw1+logw2+logwk。这样就将乘法转变为了加分,为了求最长路,可以作取相反数处理。因为 w i ( 0 ≤ w i ≤ 1 ) w_i(0\leq w_i\leq1) wi(0wi1),所以 log ⁡ w i ≤ 0 \log w_i \leq 0 logwi0,取相反数后全是非负数,所以可以采用Dijkstra算法。

代码

#include <iostream>
#include <cstdio>
#include <cstring>
#include <algorithm>

using namespace std;

const int N = 2010;

int n,m,S,T;
double g[N][N];
double dist[N];
bool st[N];

void dijkstra()
{
    
    
    dist[S] = 1;
    for(int i=1;i<=n;i++){
    
    
        int t = -1;
        for(int j=1;j<=n;j++){
    
    
            if(!st[j]&&(t==-1||dist[t]<dist[j])){
    
    
                t = j;
            }
        }
        st[t] = true;
        for(int j=1;j<=n;j++){
    
    
            dist[j] = max(dist[j],dist[t]*g[t][j]);
        }
    }
}

int main()
{
    
    
    scanf("%d%d",&n,&m);
    while(m--){
    
    
        int a,b,c;
        scanf("%d%d%d",&a,&b,&c);
        double z = (100.0 - c) / 100;
        g[a][b] = g[b][a] = max(g[a][b], z);
    }
    scanf("%d%d",&S,&T);
    dijkstra();
    printf("%.8f\n",100.0/dist[T]);
    return 0;
}

收获

  • 求最长路,可以将边权取反,做最短路。其实在写代码的过程中,不一定真的取反,只需要将三角不等式不等号反过来, m i n min min改成 m a x max max即可。
  • 对于乘法来说,权值如果是小于等于 1 1 1,那么相当于加法的负边权;如果是大于 1 1 1的话,就是正边权。

猜你喜欢

转载自blog.csdn.net/weixin_43634220/article/details/108589155