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";
}