题目传送门:【POJ 1860】
题目大意:你需要通过兑换货币来赚钱,N 座城市有 M 个货币兑换点(可看作有 N 个点和有 M 条边的图),你每兑换一次货币需要支付一定佣金才能兑换。例如,你想把 100 美元换成俄罗斯卢布,如果那里的汇率是 29.75,而佣金是 0.39,你会得到(100 - 0.39)×29.75=2963.3975 卢布。求最后能否通过不断地兑换货币使得自己的财富源源不断地增长。当然,在兑换过程中,你拥有的钱不能为负值。
题目分析:
考察对于最短路的理解及灵活的变换(运用)。
本题的目的是要让主人公不断地通过兑换货币获利,如果在这个图上有正环,那么只要不停地沿着正环走,那么财富就会不断增长,此时就满足题意了。
因此,这道题在初始化时,应该与普通的最短路算法相反,初始化为非常小的值。此时判断正环即与原来的判断负环的方式相反。(当然,判断的思路是一样的。)
下面附上代码:
#include<cstdio>
#include<cstring>
#include<iostream>
#include<queue>
using namespace std;
const int MX=10005;
struct Edge{
int to,next;
double rate,com;
};
Edge edge[MX];
int n,m,w,now = 0,head[MX];
double ori; //原有的货币数量
void adde(int u,int v,double r,double c){
edge[++now].to = v;
edge[now].rate = r,edge[now].com = c;
edge[now].next = head[u];
head[u] = now;
}
bool spfa(int s){
queue<int> q;
int cnt[MX] = {0};
double dis[MX]; //在这个点所有的钱的最大值
bool vis[MX];
memset(dis,0xef,sizeof(dis));
dis[s] = ori,vis[s] = true,q.push(s);
while (!q.empty()){
int u = q.front();
q.pop();
for (int i = head[u];i;i = edge[i].next){
int v = edge[i].to;
if ((dis[u] - edge[i].com) * edge[i].rate > dis[v]){
dis[v] = (dis[u] - edge[i].com) * edge[i].rate;
//判断的方式有改变。这里,如果兑换后的钱比原来的多,那么就更新;否则不变
cnt[v]++;
q.push(v);
vis[v] = true;
if (cnt[v] >= n) return true;//判断正环
}
}
}
return false;
}
int main(){
int a,b;
double p1,q1,p2,q2; //p:汇率, q:佣金
cin>>n>>m>>w>>ori;
for (int i = 1;i <= m;i++){
cin>>a>>b>>p1>>q1>>p2>>q2;
adde(a,b,p1,q1);
adde(b,a,p2,q2);
}
if (spfa(w)) cout<<"YES"<<endl;
else cout<<"NO"<<endl;
}