POJ 1860 - Currency Exchange - Bellman Ford
Currency Exchange
描述
我们城市里有各种货币兑换点。让我们假设每个点专门针对两种特定的货币,并且只使用这些货币执行交换操作。
同一对货币可以有几个点。每一个点都有自己的汇率,A对B的汇率就是1A得到的B的数量。
此外,每个兑换点都有一些佣金,这是您兑换业务所需支付的金额。佣金总是以原始货币收取。
例如,如果您想在兑换点将100美元兑换成俄罗斯卢布,兑换率为29.75,佣金为0.39,您将得到 (100 - 0.39) 29.75 = 2963.3975卢布。
你一定知道在我们城市有N种不同的货币可以交易。让我们为每种货币分配从1到N的唯一整数。
然后每个兑换点可以用6个数字来描述:交换货币的整数A和整数B,以及A对B和B对A分别交换时的实际Rab, Cab, Rba和Cba汇率和佣金。
Nick有一些货币S,他想知道,在一些兑换业务之后,他是否能以某种方式增加本金。
当然,他最终还是想把钱换成S货币。帮助他回答这个难题。Nick此操作一定要有一笔非负的钱。
Input
输入的第一行包含四个数字:N-货币种类数量,M-货币兑换点数量,S-Nick拥有的货币,V-他拥有的货币单位数量。
以下M行按上述顺序分别包含6个数字-对应交换点的描述,按上述顺序。数字由一个或多个空格分隔。
1<=S<=N<=100, 1<=M<=100,V为实数, 0<=V<=10^3。
每一点的汇率和佣金都是实数,小数点后最多有两位数,10^-2<=rate<=10^2, 0<=commission<=10^2。
如果在这个序列中没有交换点被多次使用,让我们将交换操作的某个序列称为简单序列。
您可以假设在任何简单的交换操作序列的末尾和开头的和的数值的比率将小于10^4。
Output
如果Nick可以增加他的财富,那么输出YES,在其他情况下输出NO到输出文件。
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
思路分析:
因为兑换过程有可能盈利有可能亏损,涉及到负权环,因此使用贝尔曼福特算法
此题目中Nick想增加本金,要求的是正权环,那么松弛的比较和平时相反
import java.util.Scanner;
/**
*
* 思路:因为兑换过程有可能盈利有可能亏损,涉及到负权环,因此使用贝尔曼福特算法
* 此题目中Nick想增加本金,要求的是正权环,那么松弛的比较和平时相反
*
* @author XA-GDD
*
*/
public class E_CurrencyExchange {
static int N,M,S;
static double V;
static CurrencyExchange[] srcArr;
static int edge = 0;
static double maxProfit [];
public static void main(String[] args) {
Scanner sc = new Scanner(System.in);
N = sc.nextInt(); //货币种类数量
M = sc.nextInt(); //货币兑换点数量
S = sc.nextInt(); //Nick拥有的货币
V = sc.nextDouble(); //Nick本金
srcArr = new CurrencyExchange[M*2+2];
maxProfit = new double[M*2+2];
for(int i=0;i<M;i++) {
int currencyA = sc.nextInt();
int currencyB = sc.nextInt();
double Rab = sc.nextDouble();
double Cab = sc.nextDouble();
double Rba = sc.nextDouble();
double Cba = sc.nextDouble();
srcArr[edge++] = new CurrencyExchange(currencyA,currencyB,Rab,Cab);
srcArr[edge++] = new CurrencyExchange(currencyB,currencyA,Rba,Cba);
}
sc.close();
System.out.println(bellmanFord()?"YES":"NO");
}
static boolean bellmanFord() {
maxProfit[S] = V;
for(int i=1;i<=N;i++) { //货币种类数量,即点的数量
boolean relaxFlag = false;
for(int j=0;j<edge;j++) { //兑换次数,即边的数量
if(maxProfit[srcArr[j].currencyB] < (maxProfit[srcArr[j].currencyA]-srcArr[j].commission)*srcArr[j].exchangeRate) {
maxProfit[srcArr[j].currencyB] = (maxProfit[srcArr[j].currencyA]-srcArr[j].commission)*srcArr[j].exchangeRate;
relaxFlag = true;
}
}
if(!relaxFlag) { //无松弛操作时,所有点的最值已求出,不必再遍历
break;
}
}
//如果兑换过程中,出现盈利,则返回true
for(int i=0;i<edge;i++) {
if(maxProfit[srcArr[i].currencyB] < (maxProfit[srcArr[i].currencyA]-srcArr[i].commission)*srcArr[i].exchangeRate) {
return true;
}
}
return false;
}
}
class CurrencyExchange{
int currencyA; //A币种
int currencyB; //B币种
double exchangeRate; //对换率
double commission; //佣金
CurrencyExchange(int currencyA,int currencyB,double exchangeRate,double commission){
this.currencyA = currencyA;
this.currencyB = currencyB;
this.exchangeRate = exchangeRate;
this.commission = commission;
}
}
浙公网安备 33010602011771号