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 ...
随机推荐
- CMD命令获取电脑所有连接过的WiFi密码
cmd中输入命令:for /f "skip=9 tokens=1,2 delims=:" %i in ('netsh wlan show profiles') do @echo ...
- zoj 3716 Ribbon Gymnastics【神奇的计算几何】
题目:http://acm.zju.edu.cn/onlinejudge/showProblem.do?problemCode=3716 来源:http://acm.hust.edu.cn/vjudg ...
- Java语言实现简单FTP软件------>源码放送(十三)
Java语言实现简单FTP软件------>FTP协议分析(一) Java语言实现简单FTP软件------>FTP软件效果图预览之下载功能(二) Java语言实现简单FTP软件----- ...
- MySQL一些常见查询方式
1.查询端口号命令: show global variables like 'port'; 2.查看版本号: select version(); 3.查看默认安装的MySQL的字符集 show var ...
- Apache Shiro 使用手册(二)Shiro 认证(转发:http://kdboy.iteye.com/blog/1154652)
认证就是验证用户身份的过程.在认证过程中,用户需要提交实体信息(Principals)和凭据信息(Credentials)以检验用户是否合法.最常见的“实体/凭证”组合便是“用户名/密码”组合. 一. ...
- sql查询字段是否为空
sql 查询某字段为空 select * from 表名 where 字段名 is null sql 查询某字段不为空 select * from 表名 where 字段名 is not null s ...
- Python 3 mysql 数据类型
Python 3 mysql 数据类型 存储引擎决定了表的类型,而表内存放的数据也要有不同的类型,每种数据类型都有自己的宽度,但宽度是可选的 详细参考: http://www.runoob.com/m ...
- 如何阻止form表单中的button按钮提交
<form action="#" method="post"> <input type="text" name=" ...
- <linux是怎么跑的?>傻瓜视角看linux引导启动过程
每天开机关机,除了“等”之外,你得了解你的操作系统开机的时候真正做了什么? 一. 书上都是这么讲的 CPU自身初始化:硬件初始工作,以PC/IP寄存器跳转到BIOS首地址为结束标志. ->加电自 ...
- POJ1182 食物链 并查集
#include<iostream>#include<stdio.h>#include<string.h>using namespace std;const int ...