[洛谷P1931] 套利
Description
给定多组数据 每组数据给定n种货币 再给定m种货币之间的汇率 求是否存在一个环 使得汇率的积>1 即盈利
Solution
将每一中货币看作点 汇率看作边权
我们可以利用SPFA进行判断环 当一个点进行的松弛操作>=n时,即出现了一个环
这里要用最长路 将括号里的加号改为乘号 可以证明如果环上所有边
的权值之积大于1,那么一定可以用SPFA判定出有向图中存在环
因为如果小于1的话肯定越乘越小啊
无法出现盈利的情况有:
1 没有环 即最后没法回到原来的货币
2 有环 但是小于1
(有可能你要问程序里并没有判断是不是>1啊 你可以想想这是最长路)
Code
![](https://images.cnblogs.com/OutliningIndicators/ContractedBlock.gif)
1 #include <iostream>
2 #include <cstdio>
3 #include <map>
4 #include <cstring>
5 #include <queue>
6 using namespace std;
7 int n, m, num, head[100], ok;
8 int vis[100], times[100];
9 double dis[100];
10 string s, ee;
11 map<string, int> mp;
12 struct emmm {
13 int next, to;
14 double dis;
15 }e[10000];
16 void add(int from, int to, double dis) {
17 e[++num].next = head[from];
18 e[num].to = to;
19 e[num].dis = dis;
20 head[from] = num;
21 }
22 int spfa(int s) {
23 memset(times, 0, sizeof(times));
24 memset(vis, 0, sizeof(vis));
25 memset(dis, 0, sizeof(dis));
26 queue<int>q;
27 q.push(s);
28 vis[s] = 1;
29 times[s] = 1;
30 dis[s] = 1.0;
31 while (!q.empty()) {
32 int now = q.front();
33 q.pop();
34 vis[now] = 0;
35 for (int i = head[now];i; i = e[i].next) {
36 int v = e[i].to;
37 if (dis[v] < dis[now] * e[i].dis) {
38 dis[v] = dis[now] * e[i].dis;
39 if (!vis[v]) {
40 vis[v] = 1;
41 q.push(v);
42 times[v]++;
43 if (times[v] >= n) return 1;
44 }
45 }
46 }
47 }
48
49 return 0;
50 }
51 int main() {
52 ios::sync_with_stdio(false);
53 cin >> n;
54 while (n) {
55 ++ok;
56 num = 0;
57 memset(e, 0, sizeof(e));
58 memset(head, 0, sizeof(head));
59 bool f = 0;
60 mp.clear();
61 for (int i = 1;i <= n; i++)
62 mp[cin >> s, s] = i;
63 cin >> m;
64 double z;
65 for (int i = 1;i <= m; i++) {
66 cin >> s >> z >> ee;
67 add(mp[s], mp[ee], z);
68 }
69 for (int i = 1;i <= n; i++)
70 if (spfa(i)) {
71 printf("Case %d: Yes\n", ok);
72 f = 1;
73 break;
74 }
75 if (f == 0) printf("Case %d: No\n", ok);
76 cin >> n;
77 }
78 return 0;
79 }