POJ 1860 Currency Exchange

我们的城市有几个货币兑换点。让我们假设每一个点都只能兑换专门的两种货币。可以有几个点,专门从事相同货币兑换。每个点都有自己的汇率,外汇汇率的A到B是B的数量你1A。同时各交换点有一些佣金,你要为你的交换操作的总和。在来源货币中总是收取佣金。 例如,如果你想换100美元到俄罗斯卢布兑换点,那里的汇率是29.75,而佣金是0.39,你会得到(100 - 0.39)×29.75=2963.3975卢布。 你肯定知道在我们的城市里你可以处理不同的货币。让每一种货币都用唯一的一个小于N的整数表示。然后每个交换点,可以用6个整数表描述:整数a和b表示两种货币,a到b的汇率,a到b的佣金,b到a的汇率,b到a的佣金。 nick有一些钱在货币S,他希望能通过一些操作(在不同的兑换点兑换),增加他的资本。当然,他想在最后手中的钱仍然是S。帮他解答这个难题,看他能不能完成这个愿望。 
Input
第一行四个数,N,表示货币的总数;M,兑换点的数目;S,nick手上的钱的类型;V,nick手上的钱的数目;1<=S<=N<=100, 1<=M<=100, V 是一个实数 0<=V<=103. 接下来M行,每行六个数,整数a和b表示两种货币,a到b的汇率,a到b的佣金,b到a的汇率,b到a的佣金(0<=佣金<=102,10-2<=汇率<=102)  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
  
  
这个题写的还是很悲催的,一开始觉得不会错,然而交了好多wa,卡了四个多小时,就因为传参的时候,把double型,传成了int型,导致精度损失,以至于一直wa。
题意是我在Vjudge上粘贴的(如有冒犯原翻译者,还请原谅),因为这道题会出现负边权,所以不能用Dijkstra,数据范围100以内,所以用Floyd或者Bellman都可以,接下来有两种写法。
Floyd, 跑两遍Floyd,第一遍是确定a转化成b,得到的多少钱,然后再进行一次转化,如果第二次的前多于第一次的钱(只要满足一个即可)就输出YES
#include <stdio.h>
#include <string.h>
double dis[105];
double mon[105];
double e1[105][105];
double e2[105][105];
bool Floyd(int v, int n, int s) {
	for(int i = 1; i <= n; i++) {
		dis[i] = mon[i];
	}
	for(int k = 1; k <= n; k++) {
		for(int i = 1; i <= n; i++) {
			for(int j = 1; j <= n; j++) {
				if(mon[j] < (mon[i] - e2[i][j])*e1[i][j])
				mon[j] = (mon[i]-e2[i][j])*e1[i][j];
			}
		}
	}
	for(int i = 1; i <= n; i++) {
		if(mon[i] > dis[i])
		return true;
	}
	return false;
}
int main() {
	int N, M, S;
	double V;
	int a, b;
	double rat1, com1, rat2, com2;
	scanf("%d %d %d %lf", &N, &M, &S, &V);
	for(int i = 0; i < M; i++) {
		scanf("%d %d %lf %lf %lf %lf", &a, &b, &rat1, &com1, &rat2, &com2);
		e1[a][b] = rat1; e2[a][b] = com1;
		e1[b][a] = rat2; e2[b][a] = com2;
	}
	mon[S] = V;
	Floyd(V, N, S);
	if(Floyd(V, N, S)) printf("YES\n");
	else printf("NO\n");
	return 0;
}


Bellman,将所拥有的钱兑换成所有可以兑换的钱,并且把金额记录下来,然后再将兑换过的钱,兑换成原来的钱,判断两次钱的数目大小即可
#include <stdio.h>
#include <string.h>
struct node{
	int s, e;
	double rat, com;
	void Node(int a, int b, double c, double d) {
		s = a; e = b;
		rat = c; com = d;
	}
}map[220];
double dis[105];
bool Bellman(double v, int n, int s, int m) {
	for(int i = 1; i <= n; i++) {
		dis[i] = 0;
	}
	dis[s] = v;
	for(int i = 1; i < n; i++) {
		bool flag = false;
		for(int j = 0; j < m; j++) {
			int u = map[j].s;
			int v = map[j].e;
			if(dis[v] < (dis[u] - map[j].com)*map[j].rat) {
				flag = true;
				dis[v] = (dis[u] - map[j].com)*map[j].rat;
			}
		}
		if(!flag) return false;
	}
	for(int j = 0; j < m; j++) {
		int u = map[j].s;
		int v = map[j].e;
		if(dis[v] < (dis[u] - map[j].com)*map[j].rat) {
			return true;
		}
	}
	return false;
}
int main() {
	int N, M, S;
	double V;
	int a, b;
	double rat1, com1, rat2, com2;
	scanf("%d %d %d %lf", &N, &M, &S, &V);
	int t = 0;
	for(int i = 0; i < M; i++) {
		scanf("%d %d %lf %lf %lf %lf", &a, &b, &rat1, &com1, &rat2, &com2);
		map[t++].Node(a, b, rat1, com1);
		map[t++].Node(b, a, rat2, com2);
	}
	if(Bellman(V, N, S, t)) printf("YES\n");
	else printf("NO\n");
	return 0;
}








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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值