题目大意
给定n中货币,及m中汇率关系,问是否能实现套利。
解题思路
该题与poj1860类似,均可用Bellman_Ford的思想求解。
Bllman_Ford用于求解任意权值的单元最短路径,并判断图中是否包含有带负权值的回路。
类似地,对于该问题,可以理解为求最长路径问题,并判断图中是否有回路,若有则能实现套利,否则不能实现。利用Bellman_Ford求解该问题是松弛条件是与Bellman_Ford相反的。
Bellman_Ford算法步骤
给定图G(V, E)(其中V、E分别为图G的顶点集与边集),源点s
数组d[i]记录从源点s到顶点i的路径长度
Bellman_Ford(){
初始化dist数组
for i ← 1 to |V[G]| - 1
do for each edge (u, v) ∈ E[G]
do RELAX(u, v, w)
for each edge (u, v) ∈ E[G]
do if d[v] > d[u] + w(u, v)
then return FALSE
return TRUE
}
Bellman_Ford算法参考http://www.wutianqi.com/?p=1912
注意:因为m种汇率关系中可能包含从美元到美元的汇率关系这种情况。
代码
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#define LEN 100
char curr[35][LEN];
double dist[35];
int n,m;
struct Edge{
int u;
int v;
double rate;
};
struct Edge edge[1200];
int relax(int u,int v,double rate){
double tmp = dist[u]*rate;
if(dist[v]<tmp){
dist[v] = tmp;
return 1;
}
return 0;
}
int Bellman_Ford(){
int i,j,k,tag;
for(i=1;i<=n;i++)
dist[i] = -1.0;
dist[edge[1].u] = 1.0;
for(k=1;k<n;k++){
for(i=1;i<=m;i++)
relax(edge[i].u,edge[i].v,edge[i].rate);
}
tag = 0;
for(i=1;i<=m;i++){
if(relax(edge[i].u,edge[i].v,edge[i].rate)){
tag = 1;
break;
}
}
return tag;
}
int main()
{
int i,j,k,tag,flag;
double rate;
char a[LEN],b[LEN];
for(k=1;;k++){
scanf("%d",&n);
if(n==0)
break;
memset(curr,0,sizeof(curr));
for(j=1;j<=n;j++){
scanf("%s",curr[j]);
}
scanf("%d",&m);
for(j=1;j<=m;j++){
memset(a,0,sizeof(a));
memset(b,0,sizeof(b));
scanf("%s %lf %s",a,&rate,b);
flag = 0;
for(i=1;i<=n;i++){
if(strcmp(a,curr[i])==0){
edge[j].u = i;
flag++;
}
if(strcmp(b,curr[i])==0){ //a.不能使用else if
edge[j].v = i;
flag++;
}
if(flag==2)
break;
}
edge[j].rate = rate;
}
tag = Bellman_Ford();
if(tag){
printf("Case %d: Yes\n",k);
}else{
printf("Case %d: No\n",k);
}
}
return 0;
}