题意:套利,一个US币换取0.5 British pound,而1 British pound 换取10.0 French francs,同时 1 French franc buys 0.21 US dollar. 那么1 US dollar 可以换取 0.5 * 10.0 * 0.21 = 1.05 US dollars ,通过一系列换取得到1.05US币,那么就可以从中获取利润,问:给出一些货币,以及兑换率,问是否可以从中获利
题解:这里可以用最短路的方法解决:我们在边的结构体 添加兑换率,然后松弛过程中,不同于最短路的取小,我们要让它获利就要取大,那么我们在spfa之前的dis初始化的时候,我们就全部memset为0,dis[src] 源点就赋值 1.这样我们就可以按照上面的方式松弛操作,然后判断是否构成负环。。如果可以,那么意思就是dis 会越来越大,spfa 用cnt[i]表示 i 入队的次数,i的入队次数大于 顶点数就说明构成负环
上马:
#include <iostream>
#include <map>
#include <string>
#include <cstring>
#include <queue>
using namespace std;
#define MAX 35
int N,M;
struct Edge{
int to,next;
double rate;
}edge[MAX*MAX];
int head[MAX];
void add(int u,int v,double rate,int i)
{
edge[i].to = v;
edge[i].rate = rate;
edge[i].next = head[u];
head[u] = i;
}
double dis[MAX];
int cnt[MAX];
bool flag[MAX];
bool spfa()
{
memset(flag,false,sizeof(flag));
memset(cnt,0,sizeof(cnt));
memset(dis,0,sizeof(dis));
dis[0] = 1;
flag[0] = true;
cnt[0] = 1;
queue<int> q;
q.push(0);
while(!q.empty())
{
int u = q.front(); q.pop();
flag[u] = false;
for(int i = head[u]; i != -1; i = edge[i].next)
{
int v = edge[i].to;
double rate = edge[i].rate;
if(dis[v] < dis[u]*rate){
dis[v] = dis[u]*rate;
if(!flag[v]){
q.push(v);
flag[v] = true;
cnt[v] ++;
}
}
if(cnt[v] > N) return true;
}
}
return false;
}
int main()
{
string a,b;
double rate;
int cas = 1;
while(cin >> N)
{
if(!N) break;
map<string,int>m;
for(int i = 0; i < N; i ++) {
cin >> a;
m[a] = i;
}
cin >> M;
memset(head,-1,sizeof(head));
for(int i = 0; i < M; i ++){
cin >> a >> rate >> b;
int u = (*m.find(a)).second;
int v = (*m.find(b)).second;
add(u,v,rate,i);
}
cout << "Case " << cas++ << ": ";
if(spfa()) cout << "Yes" <<endl;
else cout << "No" <<endl;
}
return 0;
}