poj1860 Currency Exchange 最短路变形 spfa 判环 思考

                                       POJ 1860

题目大意:

有个城市有m种货币,n个货币兑换站。每两种货币兑换分别有相应的汇率和手续费。

例如,你现在有s个A货币,那么用A货币兑换B货币,你可得到(s-cab(A兑换B的手续费))*Rab(A兑换B的汇率)个B货币。

你现在有第S种货币V个,然后问你,是否能通过一系列的兑换,使得最后自己手中的第S种增加了。。。

大致思路:

此题要用最短路的思想进行求解,dis[i]代表当我兑换了第i种货币时,能兑换的数量。那么要使得原来的货币数量增加,那肯定是通过一系列的兑换之后,使得dis[start]>dis[start](开始的,即V)。

既然能回来,那说明一定会有环。既然有环,我们就要使用Bellman-Ford算法或者spfa。这两种都是可以进行存在环的的寻求最短路算法。我选用的是spfa算法,当存在dis[start]>V时就说明成功了。

此题和原来的最短路思想恰好相反,我们要把dis数组初始化为0。然后当兑换的货币数量大于原来的,就进行松弛。

代码:

#include<stdio.h>
#include<iostream>
#include<string.h>
#include<vector>
#include<queue>
using namespace std;
double dis[105];
int vis[105];
int m,n,s;
double v;
struct Node
{
    int to;
    double rat,cos;
    Node(int too,double ratt,double coss)
    {
        to=too;
        rat=ratt;
        cos=coss;
    }
};
vector<Node>V[105];//用vector存图
void init()
{
    for(int i=1; i<=105; i++)
        V[i].clear();
    int a,b;
    double rab,cab,rba,cba;
    for(int i=0; i<n; i++)
    {
        scanf("%d%d%lf%lf%lf%lf",&a,&b,&rab,&cab,&rba,&cba);
        V[a].push_back(Node(b,rab,cab));
        V[b].push_back(Node(a,rba,cba));
    }
    return;

}
int spfa()//我们要的是spfa的这种思想,这题并不是求最短路。。
{
    queue<int>Q;
    while(!Q.empty())Q.pop();
    for(int i=0; i<=105; i++)
    {
        dis[i]=0;//初始化成0.当兑换第i种货币时,若大于原来的,就进行松弛。
        vis[i]=0;
    }
    dis[s]=v;
    Q.push(s);
    vis[s]=1;
    while(!Q.empty())
    {
        int top=Q.front();
        Q.pop();
        vis[top]=0;
        for(int i=0;i<V[top].size();i++)
        {

            if(dis[V[top][i].to]<(dis[top]-V[top][i].cos)*V[top][i].rat)
            {
                  dis[V[top][i].to]=(dis[top]-V[top][i].cos)*V[top][i].rat;//cout<<"++"<<dis[V[top][i].to]<<endl;
                  if(!vis[V[top][i].to])
                  {
                      Q.push(V[top][i].to);
                      vis[V[top][i].to]=1;
                  }
            }
            if(dis[s]>v)//增值了,成功了
                return 1;
        }
    }
    return 0;
}
int main()
{

    scanf("%d%d%d%lf",&m,&n,&s,&v);
    init();
    if(spfa())
        printf("YES\n");
    else
        printf("NO\n");

}




评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值