Currency Exchange_POJ-1860 (SPFA、Floyd 判断正权环)

本文探讨了如何通过一系列货币兑换操作,在支付手续费的情况下,利用特定的算法判断是否能够增加初始资本。通过Floyd和SPFA算法,分析了货币兑换点的汇率和手续费,以确定是否存在正环,即能否通过多次兑换最终增加资本。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

                                          Currency Exchange

Time Limit: 1000MS Memory Limit: 30000K
Total Submissions: 42032 Accepted: 16144

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 RAB, CAB, RBA and CBA - 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<=103. 
For each point exchange rates and commissions are real, given with at most two digits after the decimal point, 10-2<=rate<=102, 0<=commission<=102. 
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 104. 

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
  • 故事依旧很长,就是说在小镇上有个货币兑换处(类似于银行),每个银行能实现两种货币的兑换,每个银行都有自己的汇率,并且还要手续费。。。
  • 兑换公式是:(本金-手续费)*汇率
  • 有个叫尼克的人,想通过乱七八糟的货币兑换来增加自己的money,问你能不能实现
  • 哪有这种好事,要是能实现,我也不告诉他,我要自己去挣钱,嘻嘻嘻

看了两遍没看出这个题的原型是什么,吃饭的时候灵光一闪,其实每种货币就是一个点,每个银行就是一个可以双向进行的路,其实就是连接在这能交易的两种货币(点)的  环          如果你想赚money,就必须保证这是一个正环,可能一次并不能挣到钱,万一手续费很高呢?但即使它是一个一次只能增加一点点的正环,但通过好多次的轮回,就能赚回本金,这叫积土成山定理

  • 那么怎么才能判断正权环呢???今天早上刚做了一个判断负权环的题,其实正负权环的判定也挺类似
  • 这是一篇判断负权环的blog

  • 同样我在这里用了FloydSPFA两个方法,其实都是套板子,啊哈哈哈哈哈哈哈哈哈哈~~~

  • 奉上我卑微的暴力枚举Floyd代码先:
#include<iostream>
#include<cstdio>
#include<cstring>
#include<algorithm>
using namespace std;
const int mm=105;
int n,m,s;
double v;
double money[mm],hui[mm][mm],tip[mm][mm];
int floyd(){
	double d[mm];//money的备份 
	for(int i=1;i<=n;i++)
		d[i]=money[i];
	for(int k=1;k<=n;k++)
	   for(int i=1;i<=n;i++)
	      for(int j=1;j<=n;j++)
	      	if((money[i]-tip[i][j])*hui[i][j]>money[j])//increase 
			  	money[j]=(money[i]-tip[i][j])*hui[i][j];
	for(int i=1;i<=n;i++)
		if(d[i]<money[i])
			return 1;//ojbk 
	return 0;
}
int main()
{
	scanf("%d%d%d%lf",&n,&m,&s,&v); 
	while(m--){
		int a,b;
		double c,d,e,f;
		scanf("%d%d%lf%lf%lf%lf",&a,&b,&c,&d,&e,&f);
		hui[a][b]=c;	tip[a][b]=d;
		hui[b][a]=e;	tip[b][a]=f;
	}
	money[s]=v;
	
	floyd();//不写为什么会错??? 
	
	if(floyd())printf("YES\n");
	else printf("NO\n");
	return 0;
}

 

  • 再来一篇高大上的SPFA代码:
#include<cstdio>
#include<string>
#include<cmath>
#include<cstring>
#include<iostream>
#include<algorithm>
#include<vector>
#include<stack>
#include<queue>
#define ll long long
#define mem(a,b) memset(a,b,sizeof(a))
using namespace std;
const int inf=0x3f3f3f3f;
const int mm=111;

int n,m,s;
double v;
int a,b;
double money[mm];//本金 
double rab,rba,cab,cba;

int cnt;
int head[mm<<1];
struct node{
	int a,b;
	double r,c;
	int next;
}pp[mm<<1];
void add(int a,int b,double r,double c){
	pp[cnt].a=a;
	pp[cnt].b=b;
	pp[cnt].r=r;
	pp[cnt].c=c;
	pp[cnt].next=head[a];
	head[a]=cnt++;
}

int book[mm];
int num[mm];//加入队列的次数 
bool spfa(){
	queue<int>q;
	q.push(s);
	book[s]=1;
	num[s]++;
	money[s]=v;
	
	while(!q.empty()){
		int u=q.front();
		q.pop();
		book[u]=0;
		for(int i=head[u];i!=-1;i=pp[i].next){
			int t=pp[i].b;
			double temp=(money[u]-pp[i].c)*pp[i].r;
			if(temp>money[t]){//涨钱了 
				money[t]=temp;
				if(book[t]==0){
					q.push(t);
					book[t]=1;
					num[t]++;
					if(num[t]>n)
						return true;
				}
			}
		}
	}
	return false;
} 

void init(){
	mem(money,0);
	mem(head,-1);
	mem(book,0);
	mem(num,0);
	cnt=0;
}

int main()
{
	init(); //不要忘了!!!
	cin>>n>>m>>s>>v;
	while(m--){
		cin>>a>>b>>rab>>cab>>rba>>cba;
		add(a,b,rab,cab);
		add(b,a,rba,cba);
	}
	if(spfa())
		printf("YES\n");
	else 
		printf("NO\n");
	  
	return 0;
}

 

评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值