POJ2240 Arbitrage

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;    
} 


發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章