T603757 市场贸易 最短路BMF

解题思路

这道题可以建模为一个单源最短路问题,目标是找到从初始商品 a 到目标商品 b 的最小花费(可能是负数)。

关键点分析

  1. 商品交换的花费计算

    • 如果 v[x] > v[y],交换后你会获得 v[x] - v[y] 元,但需要支付 1 元手续费,所以总花费是 -(v[x] - v[y]) + 1

    • 如果 v[x] < v[y],你需要支付 v[y] - v[x] + 1 元。

    • 综上,每次交换的花费可以表示为 (a[y] - a[x]) + 1(因为 a[y] - a[x] 可能是正或负)。

  2. 图建模

    • 每种商品是一个节点,交换关系是有向边。

    • 边权 = (a[y] - a[x]) + 1(即交换的花费)。

    • 问题转化为:从节点 a 出发,找到到节点 b 的最短路径(路径权值和最小)。

  3. 最短路算法选择

    • 由于边权可能是负数,不能直接用 Dijkstra(需要非负权值)。

    • 本题可以用 Bellman-Ford(BMF)算法,因为它能处理负权边,并且可以检测负环(虽然本题不需要)。

    • 由于 n 和 m 较大(n ≤ 1e5m ≤ 2e5),标准的 BMF(复杂度 O(nm))可能会超时,但题目数据可能较宽松,或者本题的 BMF 实现优化后可以通过。

#include<bits/stdc++.h>
using namespace std;
const int N = 2e5 + 10, inf = 0x3f3f3f3f;

struct node {
    int x, y, z;  // x: 当前商品, y: 目标商品, z: 交换花费 (a[y] - a[x] + 1)
};

int n, m, s, e;  // n: 商品数量, m: 商人数量, s: 起始商品, e: 目标商品
int a[N];        // a[i]: 第 i 种商品的价值
node t[N];       // t[i]: 第 i 个商人的交易信息 (x, y, z)
int dis[N];      // dis[i]: 从 s 到 i 的最小花费

// Bellman-Ford 算法求单源最短路
void BMF(int s) {
    memset(dis, inf, sizeof(dis));  // 初始化 dis 为无穷大
    dis[s] = 0;                     // 起点花费为 0

    // 松弛操作,最多进行 n-1 轮
    for (int i = 1; i < n; i++) {
        int f = 0;  // 标记本轮是否发生松弛
        for (int j = 1; j <= m; j++) {
            int x = t[j].x, y = t[j].y, z = t[j].z;

            // 如果 x 不可达,跳过
            if (dis[x] == inf) continue;

            // 如果发现更优路径,更新 dis[y]
            if (dis[y] > dis[x] + z + 1) {
                dis[y] = dis[x] + z + 1;
                f = 1;  // 标记发生松弛
            }
        }
        if (!f) break;  // 如果本轮未松弛,提前退出
    }
}

int main() {
    cin >> n >> m >> s >> e;
    for (int i = 0; i < n; i++) cin >> a[i];  // 输入商品价值

    // 构建交易图
    for (int i = 1; i <= m; i++) {
        int x, y;
        cin >> x >> y;
        t[i] = {x, y, a[y] - a[x]};  // 边权 z = a[y] - a[x],最终花费是 z + 1
    }

    BMF(s);  // 计算从 s 出发的最短路

    if (dis[e] == inf) cout << "No solution";  // 无法到达
    else cout << dis[e];                       // 输出最小花费

    return 0;
}

算法优化点

  1. Bellman-Ford 优化

    • 由于本题不需要检测负环,所以可以提前终止(当某轮未松弛时退出)。

    • 但最坏情况下仍需 O(nm) 时间,可能无法通过极限数据(n=1e5, m=2e5),但题目可能数据较水。

  2. 更优解法(SPFA)

    • 可以用 SPFA(队列优化的 Bellman-Ford),平均复杂度 O(km)k 是平均入队次数),在随机数据下更快。

    • 但极端情况下(如网格图)会退化回 O(nm)

  3. Dijkstra 不可行

    • 由于存在负权边(a[y] - a[x] + 1 可能是负的),Dijkstra 无法正确计算最短路。

posted @ 2025-05-07 14:45  CRt0729  阅读(27)  评论(0)    收藏  举报