POJ 1860 Currency Exchange && POJ 2240 Arbitrage

POJ 1860 Currency Exchange Bellman-Ford
我们市有几个货币兑换点。让我们假设每个点专门使用两种特定的货币,并且仅使用这些货币执行交换操作。可以有几个点专门针对同一对货币。每个点都有自己的汇率,A对B的汇率是你从1A中得到的B的数量。
而且每个兑换点都有一定的佣金,即你必须为兑换操作支付的金额。佣金总是以来源货币收取。
例如,如果你想在汇率为29.75,佣金为0.39的兑换点将100美元兑换成俄罗斯卢布,你将得到(100 - 0.39)* 29.75 = 2963.3975卢布。您一定知道在我们这个城市有N种不同的货币可以兑换。让我们为每种货币分配从1到N的唯一整数。然后每个汇兑点可以用6个数字来描述:整数A和B:它所兑换的货币的数量,以及实际的RAB、CAB、RBA和CBA:
分别兑换 A到 B和 B到 A时的汇率和佣金。尼克有一些货币,他想知道在做了一些外汇交易后,他能否增加资本。
当然,他最终还是想把钱换成货币S。帮助他回答这个难题。尼克在做他的生意时必须有一笔非负数的钱。

输入
第一行包含四个数字:N:货币数量,M:交换点的数量,S:Nick拥有的货币数量,V:他拥有的货币单位数量。下面的M行包含6个数字,每个数字表示对应的交换点,按上述顺序排列。数字由一个或多个空格分隔。1 < = S < = N < = 100, 1 < = M < = 100, V是实数,0 < = V < = 13。对于每一个点,汇率和佣金都是实数,小数点后最多有两位数字,10-2 <=汇率<=102, 0<=佣金<=102。如果在这个序列中没有交换点被不止一次使用,那么让我们将交换操作的某个序列称为simple的。您可以假设在任何simple的交换操作序列的末尾和开头的总和的数值之比将小于10^4。

输出
如果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

#include<iostream>
#include<cstdio>
using namespace std;
const int N = 105;
int en,n,m,s;
float v,dis[N];
struct Edge {
	int from,to;
	float r,c;
} edge[2*N];

void add(int x,int y,float R,float C) {
	edge[++en].to = y;
	edge[en].from = x;
	edge[en].c = C;
	edge[en].r = R;
}

bool bellman_ford() {
	bool f;
	for(int i=1; i<=n; i++) {
		f = false;
		for(int j=1; j<=en; j++)
			if(dis[edge[j].to]<(dis[edge[j].from]-edge[j].c)*edge[j].r) {
				dis[edge[j].to]=(dis[edge[j].from]-edge[j].c)*edge[j].r;
				f=true;
			}
		if(!f) return false;
	}
	return f;
}

int main() {
	cin>>n>>m>>s>>v;
	for(int i=1,x,y; i<=m; i++) {
		float R1,R2,C1,C2;
		cin>>x>>y>>R1>>C1>>R2>>C2;
		add(x,y,R1,C1);
		add(y,x,R2,C2);
	}
//	for(int i=1,x,y;i<=en;i++)cout<<i<<" "<<edge[i].from <<" "<<edge[i].to <<" "
//<<edge[i].c <<" "<<edge[i].r <<endl<<endl;
//输出调试找错误发现是add函数引用变量把float写成int???
	dis[s]=v;
	if(bellman_ford()) cout<<"YES"<<endl;
	else cout<<"NO"<<endl;
	return 0;
}

本题是隐藏的图论???其实是我太菜了看不出来 dis[i]表示第i种货币下最多能拿到的钱, 每次可以更新的条件是钱变多废话 如果可以找到正环就可以增加资本,所以Bellman-Ford找正环
由于好像不会爆掉就懒得写队列优化乐

2019.10.21.

补充另一个题:POJ 2240 Arbitrage

描述
套利是利用货币汇率差异将一种货币单位转换成一种以上相同货币单位。例如,假设1美元买入0.5英镑,1英镑买入10.0法国法郎,而1法国法郎买入0.21美元。然后,通过转换货币,一个聪明的交易者可以从1美元开始,买入0.5 * 10.0 * 0.21 = 1.05美元,获利5%。您的工作是编写一个程序,该程序将货币汇率列表作为输入,然后确定是否可以进行套利。
.
输入项
输入将包含一个或多个测试用例。在每个测试用例的第一行中,有一个整数n(1 <= n <= 30),代表不同货币的数量。接下来的n行分别包含一种货币的名称。名称中不会出现空格。下一行包含一个整数m,代表要跟随的表的长度。最后的m行分别包含源货币的名称ci,代表从ci到cj的汇率的实数rij和目标货币的名称cj。没有出现在表中的交换是不可能的。
测试用例之间用空白行隔开。输入以n的零(0)值终止。
.
输出量
对于每个测试用例,分别以“Case x:Yes”或“Case x:No”的格式打印一行,说明是否可以套利。x是测试点编号。
.
Sample Input
3
USDollar
BritishPound
FrenchFranc
3
USDollar 0.5 BritishPound
BritishPound 10.0 FrenchFranc
FrenchFranc 0.21 USDollar
.
3
USDollar
BritishPound
FrenchFranc
6
USDollar 0.5 BritishPound
USDollar 4.9 FrenchFranc
BritishPound 10.0 FrenchFranc
BritishPound 1.99 USDollar
FrenchFranc 0.09 BritishPound
FrenchFranc 0.19 USDollar
.
0
.
Sample Output
Case 1: Yes
Case 2: No

#include<iostream>
#include<cstdio>
#include<map>
using namespace std;
const double oo = 1000000.0;
const int N = 35;
map<string,int> m;
int n,a,en,p;
double dist[N];
struct Edge{
	int to,from;
	double w;
}edge[N*N];

bool bellman_ford(){
	bool f;
	for(int i=1;i<=n;i++){
		f = false;
		for(int j=1;j<=en;j++)
			if(dist[edge[j].to]<dist[edge[j].from]*edge[j].w){
				dist[edge[j].to]=dist[edge[j].from]*edge[j].w;
				f=true;
			}
		if(!f) return false; 
	}
	return f;
}

void add(int x,int y,double t){
	edge[++en].to = y;
	edge[en].from = x;
	edge[en].w = t;
}

int main(){
	while(cin>>n){
		p++;
		int k=0;en=0;
		if(n==0) break;
		for(int i=2;i<=n;i++) dist[i] = oo;
		dist[1]=100;
		for(int i=1;i<=n;i++){
			string s;
			cin>>s;
			m[s]=++k;
		}
		cin>>a;
		for(int i=1;i<=a;i++){
			string s1,s2;//c++字符串不能用scanf 
			double data;
			cin>>s1>>data>>s2;
			add(m[s1],m[s2],data);
		}
		if(bellman_ford()) cout<<"Case "<<p<<": Yes"<<endl;
		else cout<<"Case "<<p<<": No"<<endl;
	}
	return 0;
}

恩这个代码写的十分顺滑快速也许是我进步了!

有关的东西:

  • map映射,map<string,int> m; 前一个类型是原始类型,后面是映射到的类型;
  • string是C++字符串,不能 scanf(“%s”,s) 输入,只能这样输入C语言字符数组然后转成C++;
  • 没啥了就一个Bellman-Ford就结束了

2019.10.24.

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

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值