POJ1860 Currency Exchange 反向bellman-ford

题目大意:在一个城市中存在n中货币,编号1到n,货币之间可以进行兑换,两种货币之间的兑换率为r,兑换时的手续费为c,这就意味着,假如你有100美元想要兑换成卢布,美元和卢布之间的兑换率为29.75,手续费为0.39的话,你能得到(100-0.39)*29.75=2963.3975卢布。现在已知n种货币和m中货币之间的兑换关系,每个兑换关系包括:可以相互兑换的两种货币a和b,以及货币a对b的兑换率r1,手续费c1,和货币b对a的兑换率r2,手续费c2;给出你起始时拥有的货币种类s和价值v,问你在若干次货币兑换之后,再次兑换为s货币时的价值v1能否超过v。



分析:和HDU1217题有点相似。同样是货币兑换,只是这道题多了个手续费,还有就是可以重复兑换(由给出的样例就可以看出)。不过这两道题的思想是相同的,我们把每一种货币都看成一个点,把两种货币之间的兑换值看做是每两点之间的权值,这样,就把问题转化为了“最短路径”问题了。由于可以重复的走某条边,而且要找的值是“最大值”,甚至可以无限的大,是不是有点似曾相识的感觉呢?我们知道,bellman-ford算法中判断负权回路的方法就是因为它可以无限松弛,在n-1次循环后仍然无确定值,如果我们在比较权值的过程中纪录之间的较大值,那么用这种方法就可以判断图中是否正权回路了(可以无限松弛,无限增加)。


实现代码如下:

#include <iostream>
#include <cstdio>
#include <cstring>
using namespace std;
typedef struct node
{
    int u,v;
    double r,c;
}EDGE;
EDGE edge[220];
int n,m,start;
double sv;
double w[110];
void add(int u,int v,double r,double c)
{
    m++;
    edge[m].u=u;
    edge[m].v=v;
    edge[m].r=r;
    edge[m].c=c;
}
bool bellman_ford()
{
    memset(w,0,sizeof(w));
    w[start]=sv;
    for(int i=1;i<n;i++)
      for(int j=1;j<=m;j++)
        if(w[edge[j].v]<(w[edge[j].u]-edge[j].c)*edge[j].r)
          w[edge[j].v]=(w[edge[j].u]-edge[j].c)*edge[j].r;
    bool flag=false;
    for(int i=1;i<=m;i++)
      if(w[edge[i].v]<(w[edge[i].u]-edge[i].c)*edge[i].r)
      {
          flag=true;
          break;
      }
    return flag;
}
int main()
{
    int m1,a,b;
    double r1,r2,c1,c2;
    scanf("%d%d%d%lf",&n,&m1,&start,&sv);
    m=0;
    for(int i=0;i<m1;i++)
    {
        scanf("%d%d%lf%lf%lf%lf",&a,&b,&r1,&c1,&r2,&c2);
        add(a,b,r1,c1);
        add(b,a,r2,c2);
    }
    if(bellman_ford()) puts("YES");
    else puts("NO");
    return 0;
}


你可能感兴趣的:(POJ1860 Currency Exchange 反向bellman-ford)