poj1860

题意:有若干种货币,某些币种之间可兑换,给出各种兑换时的汇率和手续费,任何兑换都是双向的,但是两个方向的汇率和手续费可能不同,并告知你现在拥有的货币种类(只拥有一种)及数量,问是否可以通过货币建兑换最后回到本币种后钱数有所增加。

分析:普通的货币兑换一般都是用floyd。但是本题除了汇率还多出一个条件——手续费,所以不能简单地使用floyd。我用的是spfa求最长路,检查是否有环路。从自己的币种出发,如果发现正环,那么则可以不停地走环路以增加自己手中的价值,又因为所有的路都是双向的,所以当手中的价值增加的足够多之后是一定可以回到自己原有的币种的。又因为正环能使价值达到正无穷,所以回去之后价值一定增加。所以本题转化为判断是否有正环。

View Code
#include <iostream>
#include <cstdlib>
#include <cstdio>
#include <cstring>
using namespace std;

#define maxm 105
#define maxn 105

struct Edge
{
    int v, next;
    double rate, commission;
}edge[maxm * 2];

int n, m;
int s;
int head[maxn];
double v;
double dist[maxn];
bool in_queue[maxn];
int push_cnt[maxn];
int q[maxn];
int edge_cnt;

void addedge(int a, int b, double r, double c)
{
    edge[edge_cnt].v = b;
    edge[edge_cnt].next = head[a];
    edge[edge_cnt].rate = r;
    edge[edge_cnt].commission = c;
    head[a] = edge_cnt++;
}

void input()
{
    edge_cnt = 0;
    memset(head, -1, sizeof(head));
    scanf("%d%d%d%lf", &n, &m, &s, &v);
    s--;
    for (int i = 0; i < m; i++)
    {
        int a, b;
        double r, c;
        scanf("%d%d", &a, &b);
        a--;
        b--;
        scanf("%lf%lf", &r, &c);
        addedge(a, b, r, c);
        scanf("%lf%lf", &r, &c);
        addedge(b, a, r, c);
    }
}

bool spfa(int s)
{
    for (int i = 0; i < n; i++)
        dist[i] = -1;
    dist[s] = v;
    memset(in_queue, 0, sizeof(in_queue));
    memset(push_cnt, 0, sizeof(push_cnt));
    int front, rear;
    front = 0;
    rear = 0;
    q[rear++] = s;
    in_queue[s] = true;
    push_cnt[s] = 1;
    
    while (front != rear)
    {
        int u = q[front++];
        if (front == maxn)
            front = 0;
        in_queue[u] = false;
        double cur = dist[u];
        for (int i = head[u]; ~i; i = edge[i].next)
        {
            int v = edge[i].v;
            double r = edge[i].rate;
            double c = edge[i].commission;
            double temp = (cur - c) * r;
            if (temp > dist[v])
            {
                dist[v] = temp;
                //printf("%d %.2f\n", v, dist[v]);
                if (in_queue[v])
                    continue;
                q[rear++] = v;
                if (rear == maxn)
                    rear = 0;
                in_queue[v] = true;
                push_cnt[v]++;
                if (push_cnt[v] > n)
                    return true;
            }
        }
        if (dist[s] > v)
            return true;
    }        
    return false;
}

int main()
{
    //freopen("t.txt", "r", stdin);
    input();
    if (spfa(s))
        puts("YES");
    else
        puts("NO");
    return 0;
}

 

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值