← 返回编程题库
coding-currency-arbitrage-cycle-detection中等免费版2000ms未尝试

货币套利环检测(对数汇率上的 Bellman-Ford)

Currency Arbitrage Cycle Detection (Bellman-Ford on Log Rates)

开始编码

真实的 FX 交易台会持续扫描自己的报价簿,寻找三角套利——一串交易(如 USD → EUR → GBP → USD)的乘性汇率积大于 1。一旦存在这样的环,机械地沿着环换汇就能在不承担市场风险的前提下拿到比起点更多的同种货币(忽略执行延迟)。本题的任务:给定汇率矩阵,判断是否存在*任意一个*这样的盈利环。

具体地,rates[i][j] 表示 1 单位货币 i 能换到多少单位货币 j。有向环 i_0 → i_1 → … → i_k = i_0 盈利当且仅当

t=0k1rates[it][it+1]  >  1. \prod_{t=0}^{k-1} \mathrm{rates}[i_t][i_{t+1}] \;>\; 1.

算法上的关键技巧是取对数把乘性条件转成加性条件。定义边权

w(i,j)  =  log(rates[i][j])(仅当 rates[i][j]>0 时存在) w(i, j) \;=\; -\log\bigl(\mathrm{rates}[i][j]\bigr) \quad \text{(仅当 } \mathrm{rates}[i][j] > 0\text{ 时存在)}

那么环在 rate 空间乘积 > 1 当且仅当它在 weight 空间的总权严格小于 0。问题就归约到带权有向图的负环检测——这是 Bellman-Ford 的教科书应用:先把每条边松弛 V−1 轮,再做第 V 轮,任何还能继续松弛的边都证明从源点能达到一个负环。复杂度 O(V·E),V ≤ 50 且边数至多 V²,跑得飞快。(在 −log 矩阵上跑 Floyd-Warshall 是同样合法的替代方案——结束后若存在 dist[i][i] < 0 则经过节点 i 有负环——复杂度 O(V³)。)

请实现 solution(currencies: list[str], rates: list[list[float]]) -> bool,存在盈利套利环就返回 True。例如 solution(["USD","EUR"], [[1.0, 0.9],[1.2, 1.0]]) 返回 True(1 USD → 0.9 EUR → 1.08 USD,每轮 8% 无风险收益),而 solution(["USD","EUR"], [[1.0, 0.9],[1.1, 1.0]]) 返回 False(往返乘积 0.99)。rates[i][j] = 0 表示该方向没有直接报价——建边时直接跳过,而不是当成 0 权边处理。松弛比较时建议加一个微小数值容差:完全自洽的矩阵 rates[i][j] = v[i]/v[j] 应当返回 False,但 log 取整带来的极小残差不应被误判为负环。

约束条件

  • 1 ≤ N ≤ 50,N = len(currencies)
  • rates 为 N×N 非负实数矩阵;要求 rates[i][i] = 1.0
  • 0 ≤ rates[i][j] ≤ 1e6;rates[i][j] = 0 表示「i 到 j 无直接换汇边」
  • 返回 `bool`:是否存在某个有向环,其汇率乘积严格大于 1
  • 保证输入满足以上约束;超出约束的输入行为未定义

样例

Case 1 · 1x1 trivial: single currency, no possible cycle

输入: [["USD"],[[1]]]

期望: false

只有一种货币时不存在两步以上的循环;对角线 1.0 是自环(乘积恰好 1),不构成套利。

Case 2 · 2x2 unprofitable round-trip (0.9 * 1.1 = 0.99)

输入: [["USD","EUR"],[[1,0.9],[1.1,1]]]

期望: false

买卖往返:1 USD -> 0.9 EUR -> 0.99 USD,乘积 0.99 < 1,没有套利空间——买卖价差吃掉了往返收益。

Case 3 · 2x2 profitable round-trip (0.9 * 1.2 = 1.08)

输入: [["USD","EUR"],[[1,0.9],[1.2,1]]]

期望: true

1 USD -> 0.9 EUR -> 1.08 USD:每轮无风险盈利 8%。用 -log 权重的 Bellman-Ford 能检出负环 0 -> 1 -> 0(权重和为 -log(1.08) < 0)。

Case 4 · 3x3 classic triangular arbitrage (0.9 * 0.9 * 1.3 = 1.053)

输入: [["USD","EUR","GBP"],[[1,0.9,0],[0,1,0.9],[1.3,0,1]]]

期望: true

稀疏单向边构成循环 USD -> EUR -> GBP -> USD,乘积 0.9 * 0.9 * 1.3 = 1.053。矩阵中的 0 表示该方向无直接报价,Bellman-Ford 直接跳过这类边。

最近提交

还没有提交记录。

编码区

实现 solution(...)。本地运行当前支持 Python 可见样例;服务端提交会运行可见样例和隐藏测试。

加载编辑器...
计时0:00

默认展示公开样例。点击「运行样例」后会在这里显示实际输出;点击「提交评测」会进入隐藏测试。

Case 1 · 1x1 trivial: single currency, no possible cycle

输入: [["USD"],[[1]]]

期望: false

只有一种货币时不存在两步以上的循环;对角线 1.0 是自环(乘积恰好 1),不构成套利。

Case 2 · 2x2 unprofitable round-trip (0.9 * 1.1 = 0.99)

输入: [["USD","EUR"],[[1,0.9],[1.1,1]]]

期望: false

买卖往返:1 USD -> 0.9 EUR -> 0.99 USD,乘积 0.99 < 1,没有套利空间——买卖价差吃掉了往返收益。

Case 3 · 2x2 profitable round-trip (0.9 * 1.2 = 1.08)

输入: [["USD","EUR"],[[1,0.9],[1.2,1]]]

期望: true

1 USD -> 0.9 EUR -> 1.08 USD:每轮无风险盈利 8%。用 -log 权重的 Bellman-Ford 能检出负环 0 -> 1 -> 0(权重和为 -log(1.08) < 0)。

Case 4 · 3x3 classic triangular arbitrage (0.9 * 0.9 * 1.3 = 1.053)

输入: [["USD","EUR","GBP"],[[1,0.9,0],[0,1,0.9],[1.3,0,1]]]

期望: true

稀疏单向边构成循环 USD -> EUR -> GBP -> USD,乘积 0.9 * 0.9 * 1.3 = 1.053。矩阵中的 0 表示该方向无直接报价,Bellman-Ford 直接跳过这类边。