最小花费(乘法最短路)

题意

给定一个无向图,边权为 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的话,就是正边权。
  • 1
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值