Poj 1860 Currency Exchange(Bellman-Ford,SPFA解单源最短路径问题)
一、题意
有多个货币交易点,每个只能互换两种货币,兑换的汇率不同,并收取相应的手续费。有N种货币,假定你拥有第S中,数量为V,有M个兑换点。问你能不能通过兑换操作使你最后拥有的S币比起始的时候多。
二、题解
货币的交换是可以重复多次的,所以我们需要找出是否存在正权回路(在这一回路上,顶点的权值能不断增加,即能一直进行松弛),且最后得到的s金额是增加的。说到松弛我们立即会想到Bellman-Ford算法,它的特点是可以处理负权边,并能判断是否存在负环(负权回路)。本题题恰恰与bellman-Ford算法的松弛条件相反,求的是能无限松弛的最大正权路径,但是依然能够利用bellman-Ford的思想去解题。关于bellman-Ford算法请关注本博客对它的详细分析。
bellman-Ford算法的时效性较好,时间复杂度O(VE)。这里也介绍一下它的队列优化算法SPFA。它是Bellman-Ford的队列优化,时效性相对好,时间复杂度O(kE)。(k<<V)。与Bellman-ford算法类似,SPFA算法采用一系列的松弛操作以得到从某一个节点出发到达图中其它所有节点的最短路径。所不同的是,SPFA算法通过维护一个队列,使得一个节点的当前最短路径被更新之后没有必要立刻去更新其他的节点,从而大大减少了重复的操作次数。
三、java算法
bellman-Ford算法
import java.util.Scanner;
class Edge{
int startNode,endNode;
double exchangeRate;
double commission;
}
public class Main{ static Edge[] edge=new Edge[210];
static int pe;
static int N,M,S;
static double V;
static double dis[]=new double[110]; static boolean bellman_ford(){
boolean sign = false;
dis[S]=V;
for(int j=0;j<N+1;j++){
sign=false;
for(int i=0;i<pe;i++)
if(dis[edge[i].endNode]<(dis[edge[i].startNode]-edge[i].commission)*edge[i].exchangeRate){
dis[edge[i].endNode]=(dis[edge[i].startNode]-edge[i].commission)*edge[i].exchangeRate;
sign=true;
}
if(!sign)
break;
}
if(sign)
return false;
else
return true;
} public static void main(String args[]){
Scanner sc=new Scanner(System.in);
for(int i=0;i<210;i++){
edge[i]=new Edge();
}
N=sc.nextInt();
M=sc.nextInt();
S=sc.nextInt();
V=sc.nextDouble();
pe=0;
int a,b;
double rab,cab,rba,cba; for(int i=0;i<M;i++){
a=sc.nextInt();
b=sc.nextInt();
rab=sc.nextDouble();
cab=sc.nextDouble();
rba=sc.nextDouble();
cba=sc.nextDouble();
edge[pe].startNode=a;
edge[pe].endNode=b;
edge[pe].exchangeRate=rab;
edge[pe++].commission=cab;
edge[pe].startNode=b;
edge[pe].endNode=a;
edge[pe].exchangeRate=rba;
edge[pe++].commission=cba;
}
if(bellman_ford())
System.out.println("NO");
else
System.out.println("YES");
}
}
SFPA算法
import java.util.LinkedList;
import java.util.Queue;
import java.util.Scanner;
public class Main{ static int MAX_Node =110;
static int N,M,S;
static double V;
static double exchangeRate[][]=new double[MAX_Node][MAX_Node];
static double commission[][]=new double[MAX_Node][MAX_Node]; public static boolean spfa(int start){
Queue<Integer> Que=new LinkedList<Integer>();
int cnt[]=new int[MAX_Node]; //记录进入队列的次数,超过N则存在正权回路
boolean[] vst=new boolean[MAX_Node]; //记录节点是否在队列中、
double[] dis=new double[MAX_Node]; //记录每个结点的最短路径估计值
for(int i=0;i<=N;i++){
vst[i]=false;
cnt[i]=0;
dis[i]=0;
}
dis[start]=V;
vst[start]=true;
cnt[start]=1;
Que.add(start);
while(Que.size()!=0){
int u=Que.poll();
vst[u]=false;
for(int i=1;i<=N;i++){
if(exchangeRate[u][i]>0 && ((dis[u]-commission[u][i]) * exchangeRate[u][i]) > dis[i]){
dis[i]=(dis[u]-commission[u][i]) * exchangeRate[u][i]; //松弛
if(!vst[i]){
vst[i]=true;
Que.add(i);
cnt[i]++;
if(cnt[i]>=N)
return true;
}
}
}
}
return dis[S]>V;
} public static void main(String args[]){
Scanner sc=new Scanner(System.in);
int i;
N=sc.nextInt();
M=sc.nextInt();
S=sc.nextInt();
V=sc.nextDouble();
for(i=0;i<M;i++){
int a,b;
a=sc.nextInt();
b=sc.nextInt();
exchangeRate[a][b]=sc.nextDouble();
commission[a][b]=sc.nextDouble();
exchangeRate[b][a]=sc.nextDouble();
commission[b][a]=sc.nextDouble();
}
if(spfa(S))
System.out.println("YES");
else
System.out.println("NO");
}
}
版权声明:本文为博主原创文章,未经博主允许不得转载。
Poj 1860 Currency Exchange(Bellman-Ford,SPFA解单源最短路径问题)的更多相关文章
- POJ 1860 Currency Exchange / ZOJ 1544 Currency Exchange (最短路径相关,spfa求环)
POJ 1860 Currency Exchange / ZOJ 1544 Currency Exchange (最短路径相关,spfa求环) Description Several currency ...
- 最短路(Bellman_Ford) POJ 1860 Currency Exchange
题目传送门 /* 最短路(Bellman_Ford):求负环的思路,但是反过来用,即找正环 详细解释:http://blog.csdn.net/lyy289065406/article/details ...
- POJ 1860 Currency Exchange (最短路)
Currency Exchange Time Limit : 2000/1000ms (Java/Other) Memory Limit : 60000/30000K (Java/Other) T ...
- POJ 1860 Currency Exchange 最短路+负环
原题链接:http://poj.org/problem?id=1860 Currency Exchange Time Limit: 1000MS Memory Limit: 30000K Tota ...
- POJ 1860 Currency Exchange + 2240 Arbitrage + 3259 Wormholes 解题报告
三道题都是考察最短路算法的判环.其中1860和2240判断正环,3259判断负环. 难度都不大,可以使用Bellman-ford算法,或者SPFA算法.也有用弗洛伊德算法的,笔者还不会SF-_-…… ...
- SPFA解决单源最短路径
SPFA(Shortest Path Faster Algorithm): 一:基本算法 在求解单源最短路径的时候,最经典的是 Dijkstra 算法,但是这个算法对于含有负权的图就无能为力了,而 B ...
- SPFA求单源最短路径
序 求最短路径的算法有很多,各有优劣. 比如Dijkstra(及其堆(STL-priority_queue)优化),但是无法处理负环的情况: 比如O(n^3)的Floyd算法:比如Bellman-Fo ...
- POJ 1860——Currency Exchange——————【最短路、SPFA判正环】
Currency Exchange Time Limit:1000MS Memory Limit:30000KB 64bit IO Format:%I64d & %I64u S ...
- 图论 --- spfa + 链式向前星 : 判断是否存在正权回路 poj 1860 : Currency Exchange
Currency Exchange Time Limit: 1000MS Memory Limit: 30000K Total Submissions: 19881 Accepted: 711 ...
随机推荐
- 网站存储session的方案
1: ASP.NET State Service是什么 用来管理 Session 的,正常来说,Session 位于IIS进程中(其实可以理解成在服务器的内存中),当IIS重启或程序池回收会自动清空S ...
- 怎样查看电脑登录过的wifi密码?
https://jingyan.baidu.com/album/fcb5aff770f7e6edaa4a71d9.html?picindex=7
- Android系统移植与调试之------->如何修改Android设备的默认休眠时间
1.找到~/mx0831-0525/frameworks/base/packages/SettingsProvider/res/values/ defaults.xml文件 2.修改默认休眠时间 3. ...
- Linux 3 -grep
七. grep家族: 1. grep退出状态: 0: 表示成功: 1: 表示在所提供的文件无法找到匹配的pattern: 2: 表示参数中提供的文件不存在. 见如下示例: /> grep 'ro ...
- 导入android sdk samples工程报错"did you mean to use @+id instead of @+android:id?"
导入“D:\adt-bundle-windows-x86_64-20140702\sdk\samples\android-15”中的工程报错 did you mean to use @+id inst ...
- 狄利克雷卷积&莫比乌斯反演
昨天刚说完不搞数论了,刚看到一个\(gcd\)的题目dalao用这个做了,虽然比正解麻烦,还是打算学一学了 数论函数: 数论函数的定义: 数论函数亦称算术函数,一类重要的函数,指定义在正整数集上的实值 ...
- tornado源码分析
初识tornado 首先从经典的helloword案例入手 import tornado.ioloop import tornado.web class MainHandler(tornado.web ...
- vim配置与使用
Vim 是一个上古神器,本篇文章主要持续总结使用 Vim 的过程中不得不了解的一些指令和注意事项,以及持续分享一个前端工作者不得不安装的一些插件,而关于 Vim 的简介,主题的选择,以及为何使用 vi ...
- Docker-使用Dockerfile创建镜像
Dockerfile是一个文本格式的配置文件,用户可以使用Docker来快速创建自定义的镜像 基本结构 Dockerfile由一行行命令语句组成,并且支持以#开头的注释行 一般而言,Dockerfil ...
- Codeforces 294B Shaass and Bookshelf:dp
题目链接:http://codeforces.com/problemset/problem/294/B 题意: 有n本书,每本书的厚度为t[i],宽度为w[i] (1<=t[i]<=2, ...