POJ 1860 Currency Exchange 【dijkstra + 多一次松弛】

POJ 1860 Currency Exchange 【dijkstra + 多一次松弛】

题目链接:poj 1860

题目大意:
这个城市一共有N种货币,两种货币之间有兑换方式,计算公式为
(A货币-A到B佣金) * A到B的汇率 = B货币,问能不能通过不断兑
换,使初始货币增加。

Input:
第一行分别是N(货币种类)P(兑换方式数)M(初始货币种类)S(初始拥有的货币量)
接下来的P行,每一行分别是
A种类 B种类 A到B的汇率 A到B的佣金 B到A的汇率 B到A的佣金

Output:
可以使货币增加输出"YES",否则输出"NO"

具体分析:
首先,显然能想到是最短路问题,N为点数,P为路径数。要想使初始货币增加,则必须要有增益环,而这个增益环并不需要直接包含初始货币,只需能够被初始货币达到和到达初始货币。
举一个最简单的例子:样例中1到2,2到1都是负,但是2和3组成的环可以增益,就可以无限利用2和3组成的环,增加货币,感觉够了,再兑换回原始货币。
那么我们如何判断是否有增益环,完成dijkstra后,再进行一次松弛,只需一次松弛,如果再有 dist[j] 被更新那就是有增益环,如果没有就是没有,再进行多少次松弛也没有。

#include<vector>
#include<iostream>
#include<algorithm>
using namespace std;
bool slack(vector<double>& dist ,
 vector<vector<double> >& wow1 ,
 vector<vector<double> >& wow2, int N){
	for(int i=1;i<=N;i++){
		for(int j=1;j<=N;j++){
			if((dist[i] -wow2[i][j]) * wow1[i][j] > dist[j]){
				dist[j] = (dist[i] -wow2[i][j]) * wow1[i][j];
				return true;
			}
		}
	}
	return false;
}
bool dijkstra(){
	int N,P,M;
	double S;
	cin>>N>>P>>M>>S;
	//存汇率
	vector<vector<double> > wow1(N+1,vector<double > (N+1,0));
	//存佣金
	vector<vector<double> > wow2(N+1,vector<double > (N+1,0));
	for(int i=0;i<P;i++){
		int a,b;
		double c,d,e,f;
		cin>>a>>b>>c>>d>>e>>f;
		wow1[a][b] = c;
		wow2[a][b] = d;
		wow1[b][a] = e;
		wow2[b][a] = f;
	}
	vector<bool> st(N+1,false);
	vector<double> dist(N+1,0);
	dist[M] = S;
	for(int i=0;i<N-1;i++){
		int t = -1;
		for(int j=1;j<=N;j++){
			if(!st[j]&&(t==-1||dist[j]>dist[t])){
				t = j;
			}
		}
		st[t] = true;
		for(int j=1;j<=N;j++){
			dist[j] = max(dist[j],(dist[t] -wow2[t][j]) * wow1[t][j]);
		}
	}
	return slack(dist,wow1,wow2,N);
}
int main(){
	if(dijkstra())
	cout<<"YES";
	else
	cout<<"NO";
}
  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值