如果没接触过bf算法 ,先看看它的介绍吧?bellman ford算法百度百科介绍
图中的加权有向边代表汇率,我们可以发现如果把 100 单位的货币 A 换成 B,再换成 C,最后换回 A,就可以得到 100×0.9×0.8×1.4 = 100.8 单位的 A! 如果交易的金额大一些的话,赚的钱是很可观的,这种空手套白狼的操作就是套汇。 现实中交易会有种种限制,而且市场瞬息万变,但是套汇的利润还是很高的,关键就在于如何快速找到这种套汇机会呢?
借助图的抽象,我们发现套汇机会其实就是一个环,且这个环上的权重之积大于 1,只要在顺着这个环交易一圈就能空手套白狼。 图论中有一个经典算法叫做 Bellman-Ford 算法,可以用于寻找负权重环 。对于我们说的套汇问题,可以先把所有边的权重 w 替换成 -ln(w) ,这样「寻找权重乘积大于 1 的环」就转化成了「寻找权重和小于 0 的环」 就可以使用 Bellman-Ford 算法在 O(EV) 的时间内寻找负权重环,也就是寻找套汇机会。
Bellman-Ford 伪代码理解
1 2 3 4 5 6 7 8 9 10 11 12 bool Bellman-Ford(G,w,s) for each vertex v ∈ V(G): d[v] ←+∞ d[s] ←0 for i = 1 → |V|: for each edge (u,v) ∈ E(G): if d[v] > d[u] + w(u,v): d[v] = d[u] + w(u,v) for each edge(u,v) ∈ E(G): if d[v] > d[u] + w(u,v): return false return true
SPFA实际上是用队列对bf的优化 ,思路差不多
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 int SPFA (int s) { queue <int > q; bool inq[maxn] = {false }; for (int i = 1 ; i <= N; i++) dis[i] = 2147483647 ; dis[s] = 0 ; q.push(s); inq[s] = true ; while (!q.empty()) { int x = q.front(); q.pop(); inq[x] = false ; for (int i = front[x]; i !=0 ; i = e[i].next) { int k = e[i].v; if (dis[k] > dis[x] + e[i].w) { dis[k] = dis[x] + e[i].w; if (!inq[k]) { inq[k] = true ; q.push(k); } } } } for (int i = 1 ; i <= N; i++) cout << dis[i] << ' ' ; cout << endl ; return 0 ; }