最小花费 —— 最短路变形

题面

传送门
在这里插入图片描述
在这里插入图片描述

思路

假设起点为 S S S,终点为 T T T

题目想问 S S S最少是多少;

在满足 S ∗ w 1 ∗ w 2 ∗ . . . = T = 100 S*w_1*w_2*...=T=100 Sw1w2...=T=100的情况下;

其中 w i w_i wi是边权;


要使得 S S S最少,说明 w 1 ∗ w 2 ∗ . . . w_1*w_2*... w1w2...要最大;

S m i n = 100 ( w 1 ∗ w 2 ∗ . . . ) m a x S_{min} = \frac{100}{(w_1*w_2*...)_{max}} Smin=(w1w2...)max100


那现在的问题就转为求起点到终点的一条乘积最大值

接着我们要证明乘积最大值是可以套加法最小值的最短路算法;

证明

我们给 w 1 ∗ w 2 ∗ . . . w_1*w_2*... w1w2...取个log

l o g ( w 1 ∗ w 2 ∗ . . . ) = l o g ( w 1 ) + l o g ( w 2 ) + . . . log(w_1*w_2*...)=log(w_1)+log(w_2)+... log(w1w2...)=log(w1)+log(w2)+...最大;

因为 w i w_i wi小于等于 1 1 1的,因此取log后就全是非正数;

因此我们将每个数取相反数,问题就变成了单源最短路问题;


注意

因为这道题 0 < w i ≤ 1 0<w_i ≤1 0wi1,因此由上述证明处转化以后,边权是非负的

因此我们可以用迪杰斯特拉,如果没有限制 w i w_i wi,那么就可能出现负权边,就不能用迪杰斯特拉了;

我用的是SPFA

Code

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

using namespace std;

typedef long long ll;

const int N = 2e3 + 10;

int n,m,start,over;

//G(i,j)为0表示没有路 刚好不用初始化
//因为我们是乘积
double G[N][N];

double dist[N];
bool in_que[N];

void spfa(){
    queue<int> que;
    que.push(start);
    dist[start] = 1;//乘积的"0"是1 加法的"0"是0
    in_que[start] = 1;
    while(!que.empty()){
        int u = que.front();
        que.pop();
        in_que[u] = 0;
        for(int to=1;to<=n;++to){
            if(G[u][to] == 0) continue;
            if(dist[to] < dist[u]*G[u][to]){
                dist[to] = dist[u]*G[u][to];
                if(!in_que[to]){
                    que.push(to);
                    in_que[to] = 1;
                }
            }
        }
    }
}

void solve(){
    cin >> n >> m;
    for(int i=1,u,v,z;i<=m;++i){
        cin >> u >> v >> z;
                                        //变成原来的百分之(1-z%)
        G[u][v] = G[v][u] = max(G[u][v],(100.0-z)/100);
    }
    cin >> start >> over;
    spfa();
    printf("%.8lf\n",100.0 / dist[over]);
}

int main(){
    std::ios::sync_with_stdio(false),cin.tie(0),cout.tie(0);
    solve();
    return 0;
}

总结(推荐使用)

加法最小值

1.无负权边:dijkstra

2.有负权边:spfa

加法最大值

  • spfa

乘法最小值

1.>=1:dijkstra

2.>0:spfa

乘法最大值

1.0-1:dijkstra

2.>0: spfa

为什么spfa能求乘积最小和最大

在这里插入图片描述

参考资料

题解

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值