Arbitrage
Time Limit: 1000MS | Memory Limit: 65536K |
Description
Arbitrage is the use of discrepancies in currency exchange rates to transform one unit of a currency into more than one unit of the same currency. For example, suppose that 1 US Dollar buys 0.5 British pound, 1 British pound buys 10.0 French francs, and 1 French franc buys 0.21 US dollar. Then, by converting currencies, a clever trader can start with 1 US dollar and buy 0.5 * 10.0 * 0.21 = 1.05 US dollars, making a profit of 5 percent.
Your job is to write a program that takes a list of currency exchange rates as input and then determines whether arbitrage is possible or not.
Your job is to write a program that takes a list of currency exchange rates as input and then determines whether arbitrage is possible or not.
Input
The input will contain one or more test cases. Om the first line of each test case there is an integer n (1<=n<=30), representing the number of different currencies. The next n lines each contain the name of one currency. Within a name no spaces will appear. The next line contains one integer m, representing the length of the table to follow. The last m lines each contain the name ci of a source currency, a real number rij which represents the exchange rate from ci to cj and a name cj of the destination currency. Exchanges which do not appear in the table are impossible.
Test cases are separated from each other by a blank line. Input is terminated by a value of zero (0) for n.
Test cases are separated from each other by a blank line. Input is terminated by a value of zero (0) for n.
Output
For each test case, print one line telling whether arbitrage is possible or not in the format "Case case: Yes" respectively "Case case: No".
Sample Input
3 USDollar BritishPound FrenchFranc 3 USDollar 0.5 BritishPound BritishPound 10.0 FrenchFranc FrenchFranc 0.21 USDollar 3 USDollar BritishPound FrenchFranc 6 USDollar 0.5 BritishPound USDollar 4.9 FrenchFranc BritishPound 10.0 FrenchFranc BritishPound 1.99 USDollar FrenchFranc 0.09 BritishPound FrenchFranc 0.19 USDollar 0
Sample Output
Case 1: Yes Case 2: No————————————————————集训12.3的分割线————————————————————
前言:这道题写Bellman太蠢了。因为邻接矩阵,而且正在学Bellman。。。。事后再写一次spfa吧……
思路:边权是兑换率的话,一路乘下去,求最长路即可。带上源点去跑,跑完之后发现源点到自身的距离变长了,说明存在套汇,也就是说成环(且该环的值大于1,那么不存在最长路)了。觉得怎么写都行吧。
P.S. 关键是有几点需要注意:
1. 存在重边,应该取最大的那个(想一想为什么)
2. 存在自身环而且大于1,直接自己换自己
代码如下:
/*
ID: j.sure.1
PROG:
LANG: C++
*/
/****************************************/
#include <cstdio>
#include <cstdlib>
#include <cstring>
#include <algorithm>
#include <cmath>
#include <stack>
#include <queue>
#include <vector>
#include <map>
#include <string>
#include <iostream>
#define INF 0x3f3f3f3f
using namespace std;
/****************************************/
const int N = 35;
map <string, int> money;
int n, m;
bool flag;
double G[N][N], dis[N];
void Bellman(int st)
{
memset(dis, 0, sizeof(dis));
dis[st] = 1;
for(int i = 1; i < n; i++) {
for(int k = 0; k < n; k++) {
for(int j = 0; j < n; j++) {
if(dis[k] < dis[j] * G[j][k]) {
dis[k] = dis[j] * G[j][k];
if(dis[st] > 1.0) {
flag = true;
return ;
}
}
}
}
}
if(dis[st] > 1.0) flag = true;
}
int main()
{
#ifdef J_Sure
freopen("000.in", "r", stdin);
// freopen(".out", "w", stdout);
#endif
string name;
int cas = 1;
while(scanf("%d", &n)!=EOF&&n) {
memset(G, 0, sizeof(G));
flag = false;
money.clear();
for(int i = 0; i < n; i++) {
cin >> name;
money[name] = i;
}
scanf("%d", &m);
string str1, str2;
double w;
for(int i = 0; i < m; i++) {
cin >> str1 >> w >> str2;
int x = money[str1], y = money[str2];
if(!G[x][y]) {
if(x == y && w > 1)
flag = true;//自身成环且大于1无限兑换
else
G[x][y] = w;
}
else
G[x][y] = max(w, G[x][y]);//对于重边,取最大值即可
}
for(int i = 0; i < n; i++) {
Bellman(i);
if(flag) break;
}
if(flag)
printf("Case %d: Yes\n", cas++);
else
printf("Case %d: No\n", cas++);
}
return 0;
}
————————————————————集训12.4的分割线————————————————————
思路:改写成SPFA,但是用邻接表的话,重边、自环有点难写。直接上矩阵,一旦某个元素入队次数超过n就return true。
代码如下:
/*
ID: j.sure.1
PROG:
LANG: C++
*/
/****************************************/
#include <cstdio>
#include <cstdlib>
#include <cstring>
#include <algorithm>
#include <cmath>
#include <stack>
#include <queue>
#include <vector>
#include <map>
#include <string>
#include <climits>
#include <iostream>
#define INF 0x3f3f3f3f
using namespace std;
/****************************************/
const int N = 35, MAXN = 100;
map <string, int> money;
int n, m, enq[N];
bool flag, inq[N];
double dis[N], G[N][N];
int q[MAXN];
bool spfa(int st)
{
for(int i = 0; i < n; i++) {
inq[i] = enq[i] = dis[i] = 0;
}
dis[st] = 1;
int fron = 0, rear = 1;
q[fron] = st;
inq[st] = true;
enq[st]++;
while(fron < rear) {
int u = q[fron%MAXN];
fron++;
inq[u] = false;
for(int v = 0; v < n; v++) if(G[u][v]) {
if(dis[v] < dis[u] * G[u][v]) {
dis[v] = dis[u] * G[u][v];
if(!inq[v]) {
q[rear%MAXN] = v;rear++;enq[v]++;
if(enq[v] > n) return true;
inq[v] = true;
}
}
}
}
return false;
}
int main()
{
#ifdef J_Sure
freopen("000.in", "r", stdin);
// freopen(".out", "w", stdout);
#endif
string name;
int cas = 1;
while(scanf("%d", &n)!=EOF&&n) {
memset(G, 0, sizeof(G));
money.clear();
for(int i = 0; i < n; i++) {
cin >> name;
money[name] = i;
}
scanf("%d", &m);
string str1, str2;
double w;
for(int i = 0; i < m; i++) {
cin >> str1 >> w >> str2;
int x = money[str1], y = money[str2];
if(!G[x][y]) {
if(x == y && w > 1)
flag = true;//自身成环且大于1无限兑换
else
G[x][y] = w;
}
else
G[x][y] = max(w, G[x][y]);//对于重边,取最大值即可
}
if(flag || spfa(0))
printf("Case %d: Yes\n", cas++);
else
printf("Case %d: No\n", cas++);
}
return 0;
}