ZOJ 1544 / POJ 1860 Currency Exchange(bellman-ford)

具体的我就不解释了,网上有很详细的。、

http://www.cppblog.com/MemoryGarden/archive/2008/09/04/60912.html

 

题意 : 就是套汇的问题,汇率Rab, 增加了一个手续费  Cab 。。。。。。。每次的结果是  (本金 – 手续费) * 汇率,而且一个人拥有的钱的类型是已知的,拥有的value 钱的个数也是已知的, 问你能不能增值。

输入 :

3 2 1 20.0                         //钱种类个数  汇率的个数,拥有第几种钱, 拥有多少钱
1 2 1.00 1.00 1.00 1.00            //钱a, 钱b, rab, cab, rba, cba
2 3 1.10 1.00 1.10 1.00

想法: 应用bellman-ford :

         应用bellman求解最短路径(上界松弛)和最长路径(下界松弛)的时候,都是松弛  点 – 1  次, 然后再看能否再进行松弛了。如果能,就证明有环。否则为最短或者最长路径(希望错了请大家指出)

      当时看这个题的时候,被bellman求解最短路给束缚了, 即循环是  点 – 1  次, 但是这种最长路的正环不一定就在  点 – 1 次松弛后,就能让目标点符合要求,也即是说不一定能松弛连接目标点的边,因为要看d[u]与d[目标点(v)]的关系,也就是边,就像最短路得负环一样, 他们是无限的增长下去的。

所以这个题 循环的终止条件有2个 :

1。 当不能松弛的时候停止, 这样就代表这个图中没有正环,这样判断一下d[x]是否大于value就可以了。

2。 发现d[x] 〉value了,这种时候有可能是图有正环,也有可能图还没有松弛完毕,但是只要发现满足条件,就可以了。

对了,这个题还要注意精度 
 

 

我想说的是,这个题里面一定有回路,但不一定是正权回路, 所以只要有一个正权回路,就可能一直更新到初始点。。

 

#include<stdio.h> #include<math.h> #define INF 999999999 struct edge { int from,to; double r,c; } edges[210],t; int main(void) { int N,M,S; int i,j; double r,c; int from,to; double V,dist[110]; int flag,start; while( scanf(“%d%d%d%lf”,&N,&M,&S,&V) != EOF ) { for( start = 1; start <= 2*M; start+=2 ) { scanf(“%d%d”,&from,&to); edges[start].from = edges[start+1].to = from; edges[start].to = edges[start+1].from = to; scanf(“%lf%lf”,&edges[start].r,&edges[start].c); scanf(“%lf%lf”,&edges[start+1].r,&edges[start+1].c); } for( i = 1; i <= N; i++ ) dist[i] = -INF; dist[S] = V; while( dist[S] == V ) { flag = 1; for( j = 1; j <= 2*M; j++ ) { from = edges[j].from; if( dist[from] <= 0 ) continue; to = edges[j].to; r = edges[j].r; c = edges[j].c; if( dist[to] + 1e-5< (dist[from] – c) * r ) { dist[to] = (dist[from] – c) * r; flag = 0; } } if( flag ) break; } if( dist[S] > V ) printf(“YES/n”); else printf(“NO/n”); } return 0; }

    原文作者:Bellman - ford算法
    原文地址: https://blog.csdn.net/dangwenliang/article/details/5823570
    本文转自网络文章,转载此文章仅为分享知识,如有侵权,请联系博主进行删除。
点赞