《Currency Exchange》spfa(详解)

做完后梳理下这道题。
首先,题意是给我们n种货币,m个货币兑换点,然后有转换规则.问你最后经过一连串转换后,回到起点,你手上的这种货币数量有没有增多
我们将它转化为一个图的问题.
那么就是把n种货币看成n个点,把m个货币兑换点看成m条边,但是注意这条边上存的是转换规则,因为边的权值应该是转换后的货币量,我们一开始不可能知道。
那么,我们再看一下这个提问,问你回到起点后的数量,首先,我们边可以将它看成有向边,点A转换为点B的兑换规则看成一条A-B的有向边,那么B-A的兑换规则就是一条B-A的有向边。根据提问,我们最后能要回到起点,说明图中肯定存在环,而且我们回到起点后,数量要增长,那么就肯定存在一条正环。我们只需要一直判断dis[s],也就是到原点的权值是不是大于开始的v了,如果大于了,那么就说明存在正环。

注意点:我们一开始的dis[s]应该等于我们原来的数量v,这样才能通过边上的转换规则转换得到边上的权值.

#include<iostream>
#include<stdio.h>
#include<queue>
#include<algorithm>
#include<math.h>
#include<stack>
#include<map>
#include<limits.h>
#include<vector>
#include<string.h>
using namespace std;
typedef long long LL;
typedef unsigned long long ULL;
typedef pair<int,int> pii;
const int N = 1e7;
const int M = 1e5+7;
#define INF 1e7+5
#define INM INT_MIN
#define pb(a)  push_back(a)
#define mk(a,b) make_pair(a,b)
#define dbg(x) cout << "now this num is " << x << endl;
#define sd(a) scanf("%d",&a)
#define sld(a) scanf("%lld",&a)
#define sdd(a,b) scanf("%d %d",&a,&b)
#define sddd(a,b,c) scanf("%d %d %d",&a,&b,&c)
#define pr(a) printf("%d\n",a)
#define plr(a) printf("%lld\n",a)
#define pr_(a) printf("%d ",a)
#define _pr(a) printf(" %d",a)
int vis[105],n,m,s;
double dis[105],v;
struct Node
{
    int to;
    double a1,b1;//存转换规则,只存A-B的,因为看成有向边
};
vector<Node> G[105];
bool spfa(int x)
{
    memset(vis,0,sizeof(vis));
    vis[x] = 1;
    for(int i=1;i<=n;++i) dis[i] = 0;//这里应该是找最大路
    dis[x] = v;
    queue<int> Q;
    Q.push(x);
    while(!Q.empty())
    {
        int u = Q.front();
        Q.pop();
        vis[u] = 0;//消除标记
        for(int i=0;i<G[u].size();++i)
        {
            Node e = G[u][i];
            if(dis[e.to] < (dis[u]-e.b1)*e.a1)
            {
                dis[e.to] = (dis[u]-e.b1)*e.a1;
                if(!vis[e.to])
                {
                    vis[e.to] = 1;//添加标记
                    Q.push(e.to);
                }
            }
            if(dis[x] > v) return true;//判断是否存在正环了
        }
    }
    return false;
}
int main()
{
    sddd(n,m,s);
    scanf("%lf",&v);
    while(m--)
    {
        int a,b;
        double a1,b1,a2,b2;
        sdd(a,b);
        scanf("%lf %lf %lf %lf",&a1,&b1,&a2,&b2);
        Node p,q;
        p.to = b;p.a1 = a1;p.b1 = b1;
        q.to = a;q.a1 = a2;q.b1 = b2;
        G[a].pb(p);
        G[b].pb(q);
    }
    if(spfa(s)) printf("YES\n");
    else printf("NO\n");
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值