You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

3.2 KiB

This file contains ambiguous Unicode characters!

This file contains ambiguous Unicode characters that may be confused with others in your current locale. If your use case is intentional and legitimate, you can safely ignore this warning. Use the Escape button to highlight these characters.

AcWing 1126. 最小花费

一、题目描述

n 个人中,某些人的银行账号之间可以互相转账。

这些人之间转账的手续费各不相同。

给定这些人之间转账时需要从转账金额里扣除百分之几的手续费,请问 A 最少需要多少钱使得转账后 B 收到 100 元。

输入格式 第一行输入两个正整数 n,m,分别表示总人数和可以互相转账的人的对数。

以下 m 行每行输入三个正整数 x,y,z,表示标号为 x 的人和标号为 y 的人之间互相转账需要扣除 z\% 的手续费 ( z<100 )。

最后一行输入两个正整数 A,B

数据保证 AB 之间可以直接或间接地转账。

输出格式 输出 A 使得 B 到账 100 元最少需要的总费用。

精确到小数点后 8 位。

数据范围 1≤n≤2000,m≤10^5

输入样例

3 3
1 2 1
2 3 2
1 3 3
1 3

输出样例

103.07153164

二、题目解析

假设初始金钱为N,那么如果要在最后一个人的手里得到100元,可得公式:

\large N(1z_1\%)(1z_2\%)∗…∗(1z_n\%)=100

\Rightarrow

\large N=\frac{100}{(1z_1\%)(1z_2\%)∗…∗(1z_n\%)}

要想N尽可能小,那么就要让 分母尽可能大 ,即求(1z_1\%)(1z_2\%)∗…∗(1z_n\%)的最大值。

注意

最小值 最大值
优先队列 小根堆 大根堆
实现 priority_queue<PII, vector<PII>, greater<PII>> q; priority_queue<PDI> q;
更新的时候用:d[v] = d[u] * (1 - w[i]\%)

三、Dijkstra

#include <bits/stdc++.h>
using namespace std;

const int N = 2010;
const int M = 2e5 + 10;

typedef pair<double, int> PDI; // 堆中数值是浮点数,注意区别

int n, m;
double dis[N];
bool st[N];

int h[N], e[M], ne[M], idx;
double w[M]; // 边权为浮点数,与一般的题目有区别
void add(int a, int b, double c) {
    e[idx] = b, w[idx] = c, ne[idx] = h[a], h[a] = idx++;
}
int S, T;
void dijkstra() {
    priority_queue<PDI> q; // 大顶堆
    dis[S] = 1;
    q.push({1, S});

    while (q.size()) {
        auto t = q.top();
        q.pop();
        int u = t.second;
        if (st[u]) continue;
        st[u] = true;

        for (int i = h[u]; ~i; i = ne[i]) {
            int v = e[i];
            double a = 1 - w[i];
            if (dis[v] < dis[u] * a) {
                dis[v] = dis[u] * a;
                q.push({dis[v], v});
            }
        }
    }
}

int main() {
    memset(h, -1, sizeof h);
    cin >> n >> m;

    while (m--) {
        int a, b, c;
        cin >> a >> b >> c;
        double w = c * 0.01;
        add(a, b, w), add(b, a, w);
    }

    cin >> S >> T;

    dijkstra();
    printf("%.8lf\n", 100 / dis[T]);
    return 0;
}