您的位置:首页 > 其它

Arbitrae -----spfa算法 --- poj-2240-Arbitrage

2017-10-28 13:34 260 查看
Total Submissions: 17765 Accepted: 7495
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.

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.

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


#include<iostream>
#include<map>
#include<queue>
#include<string>
#include<string.h>
#include<vector>
using namespace std;
int n;
int m;
double frate[30][30];//这个相当于汇率
int center[40];//这是确定入栈的次数
double d[40];//这是确定每个点或者说是每中货币的价格
bool isvisit[40];//只是确定一下是不是被在队列中
map<string,int>  name_index;
int ncase=0;
vector<int> linjie[40];//用动态数组来做邻接表,比用链表快些
bool spfa(int s)//传入源点
{
queue<int> t;
t.push(s);//将这种货币进队
center[s]++;//进队的次序加一
d[s]=1.0;//将这种货币的默认价格设置为1
isvisit[s]=true;//是在队列中;
while(t.empty()==false)//假设队列没有空,那么不停的进出队列,并进行松弛
{
int value=t.front();//用value取出出队头的货币序号
t.pop();//队头出队
isvisit[value]=false;//出队后该序号的状态应该是不在队列中的
for(int i=0;i<linjie[value].size();i++)//遍这一点的邻接表
{
int aimindex=linjie[value][i];//每次取出与它有直接汇率关系的目标货币序号,存放在aimidex
if(d[aimindex]<d[value]*frate[value][aimindex])//进行松弛,如果说这一点的价格,乘以汇率比原先的目标货币的价值大,那么就进行兑换
{
d[aimindex]=d[value]*frate[value][aimindex];
if(isvisit[aimindex]==false)//如果说是目标货币没有在队列中
{
t.push(aimindex);//把该店加入到队尾
isvisit[aimindex]=true;//该点的状态设置成在队列中
center[aimindex]++;//进队次数加一
if(center[aimindex]>n)//如果该点的进队次数大货币的种类数,根据spfa算法,存在
return true;//退出算法.并且返回true;
}
}
}
}
return false;//如果没有返回true,说明不存在,返回false;
}

int main()
{
cin>>n;//第一次读入n
while(n!=0)//当n不等于零的时候,继续读入和处理下一个实例
{
string name;//将读入的货币种类读入到string类型的name中
name_index.clear();//每次读入新的实例之前,要把上一个实例所建立的键值对清空
memset(frate,0,sizeof(frate));//每次在读入新的汇率之前,把上一个实例的汇率清空
memset(linjie,0,sizeof(linjie));//每次在建立新的邻接表之前,把旧的邻接表清空
for(int i=0;i<n;i++)//循环读入数据
{
cin>>name;
name_index.insert(pair<string,int>(name,i));//建立键值对
}
cin>>m;
string sname,ename;//将原货币(即被兑换的货币种类记做start name,简称sname ,目标货币种类名称记做edge name 简称ename)
double rate;//汇率记做双精度类型的rate
for(int i=0;i<m;i++)//读入各个货币以及其汇率
{
cin>>sname>>rate>>ename;
int sindex,eindex;
sindex=name_index[sname];
eindex=name_index[ename];
frate[sindex][eindex]=rate;
linjie[sindex].push_back(eindex);//使用vector动态数组,建立一个图的邻接表
}
ncase++;//数据处理玩成后实例的个数加一
bool isok=false;//假设没有一个有效的圈利
for(int i=0;i<n;i++)
{
memset(center,0,sizeof(center));//每次执行spfa算法的时候,都要清空每个点的入队次数
memset(isvisit,false,sizeof(isvisit));//每次执行spfa算法的时候,都要把每个点的入队情况设置为false,每个点都设置为未进入队列的状态
memset(d,0,sizeof(d));//将每种货币的价格设置为1
if(spfa(i))//spfa算法如果返回一个true 即算法确定该实例中,至少存在一个圈利,那么isok设置为true,break掉,结束循环
{ isok=true;break;}
}

if(isok)
cout<< "Case "<<ncase<<": "<<"Yes"<<endl;//如果isok是true,打印Yes
else
cout<< "Case "<<ncase<<": "<<"No"<<endl;//否则打印No
cin>>n;//进行下一次输入n,如果是0,那么中断循环,退出程序
}
}
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: