POJ1860 Currency Exchange

Currency Exchange
Time Limit: 1000MS Memory Limit: 30000K
Total Submissions: 34789 Accepted: 13350

Description

Several currency exchange points are working in our city. Let us suppose that each point specializes in two particular currencies and performs exchange operations only with these currencies. There can be several points specializing in the same pair of currencies. Each point has its own exchange rates, exchange rate of A to B is the quantity of B you get for 1A. Also each exchange point has some commission, the sum you have to pay for your exchange operation. Commission is always collected in source currency. 
For example, if you want to exchange 100 US Dollars into Russian Rubles at the exchange point, where the exchange rate is 29.75, and the commission is 0.39 you will get (100 - 0.39) * 29.75 = 2963.3975RUR. 
You surely know that there are N different currencies you can deal with in our city. Let us assign unique integer number from 1 to N to each currency. Then each exchange point can be described with 6 numbers: integer A and B - numbers of currencies it exchanges, and real R AB, C AB, R BA and C BA - exchange rates and commissions when exchanging A to B and B to A respectively. 
Nick has some money in currency S and wonders if he can somehow, after some exchange operations, increase his capital. Of course, he wants to have his money in currency S in the end. Help him to answer this difficult question. Nick must always have non-negative sum of money while making his operations. 

Input

The first line of the input contains four numbers: N - the number of currencies, M - the number of exchange points, S - the number of currency Nick has and V - the quantity of currency units he has. The following M lines contain 6 numbers each - the description of the corresponding exchange point - in specified above order. Numbers are separated by one or more spaces. 1<=S<=N<=100, 1<=M<=100, V is real number, 0<=V<=10 3
For each point exchange rates and commissions are real, given with at most two digits after the decimal point, 10 -2<=rate<=10 2, 0<=commission<=10 2
Let us call some sequence of the exchange operations simple if no exchange point is used more than once in this sequence. You may assume that ratio of the numeric values of the sums at the end and at the beginning of any simple sequence of the exchange operations will be less than 10 4

Output

If Nick can increase his wealth, output YES, in other case output NO to the output file.

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

给定N种货币,现在有一些可以交换货币的交易所,在那里可以实现两种货币的相互转化。

每个交易所需要缴纳一定的手续费,每个交易所给出6个参数,A,B两货币的种类,A->B的汇率和手续费,B->A的汇率和手续费。给出现有的货币种类和数量,问你经过一些交易所后钱会不会变多,当然最后要转化为原始种类的货币。

因为是归类在最短路问题里面,于是一个重要的问题是如何建图以及使用何种算法。

那么建图的方式是对于每一个交易所正向转换和反向转换我们都看作一条边并记录其起点和终点,再记录汇率和手续费。

那么对于每一个点我们跑一遍bellman-ford算法

这个算法的原始形态可以用于求负环,那么其实也能用来求正环。

如果经过一轮循环以后发现值还能更新,说明 存在正环。

那么一些小优化:如果在中途发现不更新了说明所有的值都不变了那么直接return false表示没有正环。

具体的bellman-ford的松弛条件的是终点的dis值(这里用money)和起点货币转化后的值比较大小,如果后者大,那么更新。

#include <stdio.h>
#include <string.h>
#include <stdlib.h>
#include <algorithm>
#include <string>
#include <iostream>
#include <stack>
#include <math.h>
#include <queue>
#include <vector>
#include <climits>
using namespace std;
const int  Max_M= 2e3 + 10;
const int inf = 0x01010101;
int e[Max_M][2];//存储每一条边的起点和终点
double c[Max_M][2];//存储每一次转换的汇率和手续费
double Money[Max_M];
int N,M,S;
int e_cnt;//边的条数
double V;
bool bellman_ford(int s, int n, double v)
{
    for(int i = 1; i <= n; i++)
        Money[i] = 0;
    Money[s] = v;
    for(int j = 1; j < n; j++)
    {
        bool update = false;
        for(int i = 0; i < e_cnt; i++)
        {
            if(Money[e[i][1]] < (Money[e[i][0]]-c[i][1]) * c[i][0])
            {
                Money[e[i][1]] = (Money[e[i][0]]-c[i][1]) * c[i][0];
                update = true;
            }
        }
        if(update == false) return false;
    }
    for(int i = 0; i < e_cnt; i++)
        if(Money[e[i][1]] < (Money[e[i][0]]-c[i][1]) * c[i][0])
            return true;
    return false;
}
int main()
{
    // freopen("out.txt","w",stdout);
    ios::sync_with_stdio(false);
    cin.tie(0);
    cin>>N>>M>>S>>V;

    while(M--)
    {
        int a,b;
        double ci,d,ei,f;
        cin>>a>>b>>ci>>d>>ei>>f;
        e[e_cnt][0] = a;
        e[e_cnt][1] = b;//a->b边的起点和终点
        c[e_cnt][0] = ci;
        c[e_cnt][1] = d;//a->b边的汇率和手续费

        e_cnt++;

        e[e_cnt][0] = b;
        e[e_cnt][1] = a;//b->a边的起点和终点
        c[e_cnt][0] = ei;
        c[e_cnt][1] = f;//b->a边的汇率和手续费
        e_cnt++;
    }
    if(bellman_ford(S,N,V))
        cout<<"YES"<<endl;
    else cout<<"NO"<<endl;
    return 0;
}

注:cin会稍微慢一点,改为scanf则为0ms

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值