题目大意:在一个城市中存在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; }