[POJ 1860] Currency Exchange 最短路判正环(SPFA版)

题目传送门:【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;
}
  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值