POJ 1860

来源:互联网 发布:java正则表达式空格 编辑:程序博客网 时间:2024/05/10 07:54
import java.util.Scanner;public class Main{       private int n;   //全部有多少种货币       private int m;   //有多少兑换方法       private Currency[] currencies;       private double[] dis;         //解出到了第i种货币时,对应的货币值       private class Currency       {               public int s1;        //货币1               public int s2;        //货币2               public double r;     //汇率               public double c;     //手续费                              Currency( int s1,int s2,double r,double c )               {                         this.s1 = s1;                         this.s2 = s2;                         this.r = r;                         this.c = c;                                      }            }              public void Relax( Currency currency )      //主要是参考《算导》里面的松弛技术       {              if( this.dis[currency.s2] < (this.dis[currency.s1]-currency.c)*currency.r )                  this.dis[currency.s2] = (this.dis[currency.s1]-currency.c)*currency.r;       }       public boolean isIncrease()        //主要是参考《算导》里面的Bellman-Ford算法       {              for( int i=1;i<=n-1;i++ )              {                   for( int j=0;j<2*m;j++ )                   {                        this.Relax( this.currencies[j] );                   }              }              for( int i=0;i<2*m;i++ )              {                   Currency currency = currencies[i];                   if( this.dis[currency.s2] < (this.dis[currency.s1]-currency.c)*currency.r )                        return true;              }              return false;       }       Main( int n,int m,int s,double v )      //初始化       {             this.n = n;             this.m = m;             this.currencies = new Currency[2*m];             this.dis = new double[n+1];             dis[s] = v;       }       public void setM( int i,int s1,int s2,double r12,double c12,double r21,double c21 )       //设置初始值       {              this.currencies[i] = new Currency( s1,s2,r12,c12 );              this.currencies[i+1] = new Currency( s2,s1,r21,c21 );       }       public static void main(String[] args)       {              Scanner s = new Scanner(System.in);              int n = s.nextInt();              int m = s.nextInt();              int S = s.nextInt();              double v = s.nextDouble();              int i=0;              Main main = new Main( n,m,S,v );              while( i<2*m )              {                     int s1 = s.nextInt();                     int s2 = s.nextInt();                     double r12 = s.nextDouble();                     double c12 = s.nextDouble();                     double r21 = s.nextDouble();                     double c21 = s.nextDouble();                     main.setM( i,s1,s2,r12,c12,r21,c21 );    //设置所有的边                     i+=2;               }               if( main.isIncrease() )                   System.out.println( "YES" );               else                   System.out.println( "NO" );       }}


这道题目,可以这么理解:一种货币,就是图上的一个点。一种兑换方法,就是这两个点之间的一个环。当货币A的数量为V时,它到货币B的兑换方法为:(A-Cab)*Rab

上式中,Cab为A、B之间的手续费,Rab为兑换率。(A-Cab)*Rab得到的结果为A到B的权值。

题目要我们判断最终的财富是不是可以增加,也就是说,要找到最大的路径。其中,货币的兑换是可以无限次数的,换句话说,只要我们找到一个正的回路,在里面无限循环执行,那么财富肯定可以增加。现在,我们要判断的,就是是不是有这样的回路。这和《算法导论》里面的“负回路”可以说是如出一辙。

所以,我们可以参考Bellman-Ford算法(算法正确性的证明可以参照《算法导论》)

 

好了,下面是废话:

唉,还是不会抽丝剥茧那样进行归纳总结来解决问题。也是参考了《算法导论》和网上的代码http://blog.csdn.net/lyy289065406/article/details/6645778

在写完之后,还因为没弄好A,B之间的兑换关系,还卡了一会儿,才解决了问题。

看来,分析问题的能力和仔细程度还是有待提高啊。唉!!!!!!

原创粉丝点击