Description
Input
Output
Sample Input
3 2 1 20.0 1 2 1.00 1.00 1.00 1.00 2 3 1.10 1.00 1.10 1.00
Sample Output
YES
题意:有多种汇币,汇币之间可以交换,这需要手续费,当你用100A币
交换B币时,A到B的汇率是29.75,手续费是0.39,那么你可以得到
(100 - 0.39) * 29.75 = 2963.3975 B币。问s币的金额经过交换最终
得到的s币金额数能否增加
在此我们又学习了一种新的算法——bellman ford 算法。
Dijkstra算法中不允许边的权是负权,如果遇到负权,则可以采用Bellman-Ford算法。
Bellman-Ford算法能在更普遍的情况下(存在负权边)解决单源点最短路径问题。对于给定的带权(有向或无向)图 G=(V,E),其源点为s,加权函数 w是 边集 E 的映射。对图G运行Bellman-Ford算法的结果是一个布尔值,表明图中是否存在着一个从源点s可达的负权回路。若不存在这样的回路,算法将给出从源点s到 图G的任意顶点v的最短路径d[v]。
适用条件&范围
1.单源最短路径(从源点s到其它所有顶点v);
2.有向图&无向图(无向图可以看作(u,v),(v,u)同属于边集E的有向图);
3.边权可正可负(如有负权回路输出错误提示);
4.差分约束系统;
Bellman-Ford算法描述:
1,.初始化:将除源点外的所有顶点的最短距离估计值 d[v] ←+∞, d[s] ←0;
2.迭代求解:反复对边集E中的每条边进行松弛操作,使得顶点集V中的每个顶点v的最短距离估计值逐步逼近其最短距离;(运行|v|-1次)
3.检验负权回路:判断边集E中的每一条边的两个端点是否收敛。如果存在未收敛的顶点,则算法返回false,表明问题无解;否则算法返回true,并且从源点可达的顶点v的最短距离保存在d[v]中。
#include <iostream> #include<stdio.h> #include<string.h> using namespace std; int b[210][2],tol; double hy[210][2],dis[110]; bool Bellman(int s,int n,double V) { for(int i=1;i<=n;i++) dis[i]=0; dis[s]=V; for(int i=1;i<n;i++) { bool flag=0; for(int j=0;j<tol;j++) { int x1=b[j][0],x2=b[j][1]; if(dis[x2]<(dis[x1]-hy[j][1])*hy[j][0]) { flag=1; dis[x2]=(dis[x1]-hy[j][1])*hy[j][0]; } } if(flag==0)return 0; } for(int i=0;i<tol;i++) if(dis[b[i][1]]<(dis[b[i][0]]-hy[i][1])*hy[i][0]) return 1; return 0; } int main() { double v; int n,m,s; while(~scanf("%d%d%d%lf",&n,&m,&s,&v)) { tol=0; while(m--) { int a1,a2; double R1,C1,R2,C2; scanf("%d%d%lf%lf%lf%lf",&a1,&a2,&R1,&C1,&R2,&C2); b[tol][0]=a1,b[tol][1]=a2; hy[tol][0]=R1,hy[tol][1]=C1; tol++; b[tol][0]=a2,b[tol][1]=a1; hy[tol][0]=R2,hy[tol][1]=C2; tol++; } if(Bellman(s,n,v))printf("YES\n"); else printf("NO\n"); } return 0; }