http://poj.org/problem?id=2240
題目大意:輸入一些幣種,輸入這些幣種的匯率,求是否存在套匯(套匯及利用匯率之間的差異,從而將某一單位的幣種,兌換回多於一單位的同種貨幣)。
思路:建立圖論模型,每種幣種爲頂點,兩種幣種間的匯率爲一條有向邊,構造好有向網後,問題轉化爲判斷圖中是否存在某個頂點,從它出發的某條迴路權值乘積大於1,大於1則存在套匯。具體求解時,可用Bellman-ford算法求從源點出發到各個頂點v(包括源點自己)。
Bellman-ford算法實現原理爲:用一個dist數組記錄最短路徑,共更新k次(1<k<n),共n-1次,代表當前點到源點經過k條邊,求最短路徑時取最小值,依次更新。用鄰接矩正實現時時間複雜度爲n^3.
//以求最短路徑爲例,允許存在負權值邊,但不允許負權值迴路
//初始化
for (i=0;i<n;i++) //n代表頂點個數
dist[i]=edge[v0][i]; //v0代表源點,此時表示源點經過一條邊到達各個頂點V的距離長度
//一下共循環n-2更新最短路徑
for (k=2;k<n;k++)
{
for (i=0;i<n;i++)
{
for (j=0;j<n;j++)
{
if (edge[i][j]!=INF&&edge[i][j]+dist[i]<dist[j]) //如i到j有邊相連,並且此路勁更短,則更新。
{
dist[j]=dist[j]+edge[i][j];
}
}
}
}
此題只需將bellman-ford稍加變形便可實現,因套匯必形成迴路,形成迴路最多有n條邊,及只需要將最長路徑更新n次即可判斷是否存在套匯。
#include<stdio.h>
#include<stdlib.h>
#include<string.h>
#define MAX 900
#define INF 0xfffffff
char s[MAX][MAX];
typedef struct node
{
int u,v;
float w;
}node;
node map[MAX];
float dist[MAX];
int n,m;
int Max(int x,int y)
{
return x>y?x:y;
}
int bellman_ford(int v0)
{
int i,j,k;
memset(dist,0,sizeof(dist));
dist[v0]=1;
for (k=0;k<n;k++) //形成迴路,最多有n條邊,循環n次。
{
for (i=0;i<m;i++)
{
if (dist[map[i].v]<dist[map[i].u]*map[i].w)
{
dist[map[i].v]=dist[map[i].u]*map[i].w;
}
}
}
if (dist[v0]>1) //若源點幣種大於1,則使用該幣種兌換可以實現套匯。
return 1;
return 0;
}
int main()
{
int tot=0;
while (~scanf("%d",&n))
{
if (n==0)
break;
int i,j,u,v,flag=0;
char sa[MAX],sb[MAX];
float ans;
for (i=0;i<n;i++)
{
scanf("%s",s[i]);
}
scanf("%d",&m);
for (i=0;i<m;i++)
{
getchar();
scanf("%s %f %s",sa,&ans,sb);
for (j=0;j<n;j++)
{
if (strcmp(sa,s[j])==0)
u=j;
if (strcmp(sb,s[j])==0)
v=j;
}
map[i].u=u;
map[i].v=v;
map[i].w=ans;
}
for (i=0;i<n;i++)
{
if (bellman_ford(i)) //存在套匯則不需要繼續往下判斷。
{
flag=1;
break;
}
}
printf("Case %d: ",++tot);
if (flag)
{
printf("Yes\n");
}
else
{
printf("No\n");
}
}
return 0;
}