POJ ~ 2240 ~ Arbitrage (Floyd或BellmanFord)

题意:你现在有N种类型的货币,这N种类型的货币之间有M种汇率关系,然后输入M组关系,A,rate,B,表示每单位A货币可以换rate的B货币。问你有没有方法使自己的钱增多?

思路:判断是否正环。货币类型用MAP映射成数字,然后建图。把你有的货币都设置为1的本金。然后跑一边Floyd看有没有货币使得自己变多了。或者跑N遍BellmanFord看有没有哪  次出现了正环。松弛条件改为权值可以变大时,可以松弛。

坑点:注意要交C++,交G++可能会超时。

Floyd:

//#include<bits/stdc++.h>
#include<iostream>
#include<cstdio>
#include<string>
#include<cstring>
#include<map>
using namespace std;
const int MAXN = 35;
int n, m;
double d[MAXN][MAXN];
void Floyd()
{
    for (int k = 0; k < n; k++)
    {
        for (int i = 0; i < n; i++)
        {
            for (int j = 0; j < n; j++)
            {
                d[i][j] = max(d[i][j], d[i][k] * d[k][j]);
            }
        }
    }
}
int main()
{
    int CASE = 1;
    while (~scanf("%d", &n) && n)
    {
        memset(d, 0, sizeof(d));
        map<string, int> M;
        for (int i = 0; i < n; i++)
        {
            string str; cin >> str;
            M[str] = i;
            d[i][i] = 1;
        }
        scanf("%d", &m);
        while (m--)
        {
            string u, v;
            double rate;
            cin >> u >> rate >> v;
            d[M[u]][M[v]] = rate;
        }
        Floyd();
        bool flag = false;
        for (int i = 0; i < n; i++)
        {
            if (d[i][i] > 1.0) { flag = true; break; }
        }
        printf("Case %d: ", CASE++);
        if (flag) printf("Yes\n");
        else printf("No\n");
    }
    return 0;
}
/*
3
USDollar
BritishPound
FrenchFranc
3
USDollar 0.5 BritishPound
BritishPound 10.0 FrenchFranc
FrenchFranc 0.21 USDollar

3
USDollar
BritishPound
FrenchFranc
6
USDollar 0.5 BritishPound
USDollar 4.9 FrenchFranc
BritishPound 10.0 FrenchFranc
BritishPound 1.99 USDollar
FrenchFranc 0.09 BritishPound
FrenchFranc 0.19 USDollar

0
*/



SPFA(队列优化BellmanFord):

//#include<bits/stdc++.h>
#include<iostream>
#include<cstdio>
#include<string>
#include<cstring>
#include<vector>
#include<queue>
#include<map>
using namespace std;
const int MAXN = 505;
const int INF = 0x3f3f3f3f;
struct Edge
{
    int from, to/*, dist*/;       //起点,终点,距离
    double rate;
    //Edge(int u, int v, int w):from(u), to(v), dist(w) {}
    Edge(int u, int v, double w):from(u), to(v), rate(w) {}
};
struct BellmanFord
{
    int n, m;                      //结点数,边数(包括反向弧)
    vector<Edge> edges;            //边表。edges[e]和edges[e^1]互为反向弧
    vector<int> G[MAXN];           //邻接表,G[i][j]表示结点i的第j条边在edges数组中的序号
    bool vis[MAXN];                //是否在队列中
    //int d[MAXN];                   //Bellman-Ford
    double d[MAXN];
    int p[MAXN];                   //上一条弧
    int cnt[MAXN];                 //进队次数

    void init(int n)
    {
        this->n = n;
        edges.clear();
        for (int i = 0; i <= n; i++) G[i].clear();
    }

    //void add_edge(int from, int to, int dist)
    void add_edge(int from, int to, double rate)
    {
        //edges.push_back(Edge(from, to, dist));
        edges.push_back(Edge(from, to, rate));
        m = edges.size();
        G[from].push_back(m - 1);
    }

    bool bellman_ford(int s)
    {
        for (int i = 0; i <= n; i++) d[i] = -INF;
        memset(vis, 0, sizeof(vis));
        memset(cnt, 0, sizeof(cnt));
        d[s] = 1; vis[s] = true;

        queue<int> Q;
        Q.push(s);
        while (!Q.empty())
        {
            int u = Q.front(); Q.pop();
            vis[u] = false;
            for (int i = 0; i < G[u].size(); i++)
            {
                Edge& e = edges[G[u][i]];
                //if (d[u] < INF && d[e.to] > d[u] + e.dist)
                if (d[u] > -INF && d[e.to] < d[u] * e.rate)
                {
                    //d[e.to] = d[u] + e.dist;
                    d[e.to] = d[u] * e.rate;
                    p[e.to] = G[u][i];
                    if (!vis[e.to])
                    {
                        Q.push(e.to); vis[e.to] = true;
                        if (++cnt[e.to] > n) return false;//有负环
                    }
                }
            }
        }
        return true;//没有负环
    }
};
BellmanFord solve;
int main()
{
    int n, m, CASE = 1;
    while (~scanf("%d", &n) && n)
    {
        solve.init(n);
        map<string, int> M;
        for (int i = 0; i < n; i++)
        {
            string str; cin >> str;
            M[str] = i;
        }
        scanf("%d", &m);
        while (m--)
        {
            string u, v;
            double rate;
            cin >> u >> rate >> v;
            solve.add_edge(M[u], M[v], rate);
        }
        bool flag = false;
        for (int i = 0; i < n; i++)
        {
            if (!solve.bellman_ford(i)) { flag = true; break; }
        }
        printf("Case %d: ", CASE++);
        if (flag) printf("Yes\n");
        else printf("No\n");
    }
    return 0;
}
/*
3
USDollar
BritishPound
FrenchFranc
3
USDollar 0.5 BritishPound
BritishPound 10.0 FrenchFranc
FrenchFranc 0.21 USDollar

3
USDollar
BritishPound
FrenchFranc
6
USDollar 0.5 BritishPound
USDollar 4.9 FrenchFranc
BritishPound 10.0 FrenchFranc
BritishPound 1.99 USDollar
FrenchFranc 0.09 BritishPound
FrenchFranc 0.19 USDollar

0
*/



  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值