POJ #1860 Currency Exchange 最短路径算法 判断负环

Description



  题目描述在这里:链接

  更多的样例:链接

思路



  我们把每种货币看成图的顶点,而每个交换站点实现一对货币的交换,可认为增加一个交换站点就是增加两个顶点间的一个环路。从样例中可以知道,如果想要让NICK的资金增加,那么就需要存在一个权值为正的环路,使得货币总价值能够无限上升。

  所以现在的问题变成了如何判断图中是否有正环。由于货币交换后总价值可能降低,也就是说可能存在负权边,那么 Dijkstra 就不适用了,应该采用能判断负环的 Bellman_ford ,还有它的优化算法 SPFA 。由于需要判断图中是否存在能使货币总价值无限上升的正环,那么松弛边的代码也就不是原来求最短路的松弛操作了,需要变成了 dis[v] < (dis[u] - C) * R 。改了松弛操作,原本判断负环的操作也就对应的变成了判断正环。

  AC 代码如下:

  1. BFS 判断货币交换后是否增值。依据:货币交换相当于增加环路,那么从 S 出发就总能回到 S,通过 S 的值来判断其是否增值。

#include<iostream>
#include<algorithm>
#include<queue>
#include<vector>
#include<cstring>
using namespace std;
const int INF = 0x3f3f3f3f;
const int MAXN = 105;
int N, M; double V;

struct Edge{
    int to;
    double R, C;
};
vector<Edge> G[MAXN]; //G[i]代表从i出发的边,vector存储边 

void addEdge (int u, int v, double r, double c) {
    Edge tmp; tmp.to = v; tmp.R = r; tmp.C = c;
    G[u].push_back(tmp);
}

double dis[MAXN];
bool inQueue[MAXN];
//spfa算法判断dis[s]是否可能大于V (实质是BFS)
bool spfa (int s) {
    for (int i = 1; i <= N; i++) {dis[i] = 0.0; inQueue[i] = false; }
    dis[s] = V;
    queue<int> q;
    q.push(s);
    inQueue[s] = true;
    while (!q.empty()) {
        int u = q.front(); q.pop();
        inQueue[u] = false;
        for (int j = 0; j < G[u].size(); j++) {
            int v = G[u][j].to;
            double r = G[u][j].R, c = G[u][j].C;
            if (dis[v] < (dis[u] - c)*r ) {
                dis[v] = (dis[u] - c)*r;
                if (!inQueue[v]) {
                    q.push (v);
                    inQueue[v] = true;
                }
            }
        }
        if (dis[s] > V) {
            return true;
        }
    }
    return false;
}

int main(void) {
    int S;
    while (cin >> N >> M >> S >> V) {
        for (int i = 1; i <= N; i++) G[i].clear();
        for (int i = 1; i <= M; i++) {
            int u, v; double R1, C1, R2, C2;
            cin >> u >> v >> R1 >> C1 >> R2 >> C2;
            addEdge(u, v, R1, C1);
            addEdge(v, u, R2, C2);
        }
        //spfa算法判断dis[s]是否可能大于V
        if (spfa(S)) cout << "YES" << endl;
        else cout << "NO" << endl;
    }
    return 0;
}

  2.Bellman_ford 判断是否存在正环。

#include<iostream>
#include<algorithm>
#include<queue>
#include<vector>
#include<cstring>
using namespace std;
const int INF = 0x3f3f3f3f;
const int MAXN = 105;
int N, M; double V;

struct Edge{
    int to;
    double R, C;
    Edge(int v, double r, double c) : to(v), R(r), C(c) {}
};
vector<Edge> G[MAXN]; //G[i]代表从i出发的边,vector存储边 

void addEdge (int u, int v, double r, double c) {
    //Edge tmp; tmp.to = v; tmp.R = r; tmp.C = c;
    //G[u].push_back(tmp);
    G[u].push_back(Edge(v, r, c));
}

double dis[MAXN];
bool bellman_ford (int s) {
    for (int i = 1; i <= N; i++) dis[i] = 0.0;
    dis[s] = V;
    bool relaxed = false; //哨兵
    //最多更新N-1次dis数组
    for (int i = 1; i <= N-1; i++) {
        relaxed = false;
        //遍历M条边
        for (int u = 1; u <= N; u++) {
            for (int j = 0; j < G[u].size(); j++) {
                int v = G[u][j].to;
                double r = G[u][j].R, c = G[u][j].C;
                if (dis[v] < (dis[u] - c)*r ) {
                    dis[v] = (dis[u] - c)*r;
                    relaxed = true;
                }
            }
        }
        if (!relaxed) break;
    }
    //判断是否存在正环
    for (int u = 1; u <= N; u++) {
        for (int j = 0; j < G[u].size(); j++) {
            int v = G[u][j].to;
            double r = G[u][j].R, c = G[u][j].C;
            //如果还有边可以松弛,说明存在正环
            if (dis[v] < (dis[u] - c)*r ) {
                return false;
            }
        }
    }
    return true; //返回true说明图不包含正环

    //或者用spfa算法直接判断dis[s]是否大于V
}

int main(void) {
    int S;
    while (cin >> N >> M >> S >> V) {
        for (int i = 1; i <= N; i++) G[i].clear();
        for (int i = 1; i <= M; i++) {
            int u, v; double R1, C1, R2, C2;
            cin >> u >> v >> R1 >> C1 >> R2 >> C2;
            addEdge(u, v, R1, C1);
            addEdge(v, u, R2, C2);
        }
        //bellman_ford算法判断是否存在正环
        if (!bellman_ford(S)) cout << "YES" << endl;
        else cout << "NO" << endl;
    }
    return 0;
}

  3.SPFA 判断是否存在正环。 SPFA算法的模板及分析在我的另一篇博客里:链接

#include<iostream>
#include<algorithm>
#include<queue>
#include<vector>
#include<cstring>
using namespace std;
const int INF = 0x3f3f3f3f;
const int MAXN = 105;
int N, M; double V;

struct Edge{
    int to;
    double R, C;
};
vector<Edge> G[MAXN]; //G[i]代表从i出发的边,vector存储边 

void addEdge (int u, int v, double r, double c) {
    Edge tmp; tmp.to = v; tmp.R = r; tmp.C = c;
    G[u].push_back(tmp);
}

double dis[MAXN];
bool inQueue[MAXN];
int cnt[MAXN];
//spfa判断是否存在正环
bool spfa (int s) {
    memset (cnt, 0, sizeof(cnt));
    memset (dis, 0.0, sizeof(dis));
    memset (inQueue, false, sizeof(inQueue));
    dis[s] = V;
    queue<int> q;
    q.push(s);
    inQueue[s] = true;
    while (!q.empty()) {
        int u = q.front(); q.pop();
        inQueue[u] = false;
        for (int j = 0; j < G[u].size(); j++) {
            int v = G[u][j].to;
            double r = G[u][j].R, c = G[u][j].C;
            if (dis[v] < (dis[u] - c)*r ) {
                dis[v] = (dis[u] - c)*r;
                if (!inQueue[v]) {
                    q.push (v);
                    inQueue[v] = true;
                    if (++cnt[v] > N) return false;
                }
            }
        }
    }
    return true; //返回true说明图中不存在正环
}

int main(void) {
    int S;
    while (cin >> N >> M >> S >> V) {
        for (int i = 1; i <= N; i++) G[i].clear();
        for (int i = 1; i <= M; i++) {
            int u, v; double R1, C1, R2, C2;
            cin >> u >> v >> R1 >> C1 >> R2 >> C2;
            addEdge(u, v, R1, C1);
            addEdge(v, u, R2, C2);
        }
        //spfa算法判断是否存在正环
        if (!spfa(S)) cout << "YES" << endl;
        else cout << "NO" << endl;
    }
    return 0;
}

原文地址:https://www.cnblogs.com/Bw98blogs/p/8449837.html

时间: 2024-10-07 00:22:41

POJ #1860 Currency Exchange 最短路径算法 判断负环的相关文章

Dijkstra算法(求解单源最短路)详解 + 变形 之 poj 1860 Currency Exchange

/* 求解单源最短路问题:Dijkstra算法(该图所有边的权值非负) 关键(贪心): (1)找到最短距离已经确定的节点,从它出发更新与其相邻节点的最短距离: (2)此后不再关心(1)中“最短距离已经确定的节点”. 时间复杂度(大概的分析,不准确): “找到最短距离已经确定的节点” => O(|V|) "从它出发更新与其相邻节点的最短距离" => 邻接矩阵:O(|V|),邻接表:O(|E|) 需要循环以上两个步骤V次,所以时间复杂度:O(V^2) 即:在|E|较小的情况下,

图论 --- spfa + 链式向前星 : 判断是否存在正权回路 poj 1860 : Currency Exchange

Currency Exchange Time Limit: 1000MS   Memory Limit: 30000K Total Submissions: 19881   Accepted: 7114 Description Several currency exchange points are working in our city. Let us suppose that each point specializes in two particular currencies and pe

poj 1860 Currency Exchange 解题报告

题目链接:http://poj.org/problem?id=1860 题目意思:给出 N 种 currency, M种兑换方式,Nick 拥有的的currency 编号S 以及他的具体的currency(V).M 种兑换方式中每种用6个数描述: A, B, Rab, Cab, Rba, Cba.其中,Rab: 货币A 兑换 货币B 的汇率为Rab,佣金为Cab.Rba:货币B 兑换 货币 A 的汇率,佣金为Cba.假设含有的A货币是x,那么如果兑换成B,得到的货币B 就是:(x-Cab) *

poj 1860 Currency Exchange (SPFA、正权回路 bellman-ford)

链接:poj 1860 题意:给定n中货币,以及它们之间的税率,A货币转化为B货币的公式为 B=(V-Cab)*Rab,其中V为A的货币量, 求货币S通过若干此转换,再转换为原本的货币时是否会增加 分析:这个题就是判断是否存在正权回路,可以用bellman-ford算法,不过松弛条件相反 也可以用SPFA算法,判断经过转换后,转换为原本货币的值是否比原值大... bellman-ford    0MS #include<stdio.h> #include<string.h> str

poj 1860 Currency Exchange(Bellman-Ford 改)

poj 1860 Currency Exchange Description Several currency exchange points are working in our city. Let us suppose that each point specializes in two particular currencies and performs exchange operations only with these currencies. There can be several

[2016-04-13][POJ][1860][Currency Exchange]

时间:2016-04-13 23:48:46 星期三 题目编号:[2016-04-13][POJ][1860][Currency Exchange] 题目大意:货币对换,问最后能否通过对换的方式使钱变多, 分析: 直接spfa判断是否存在环,如果存在那么就能无限增值 如果不存在正环,那么直接判断最终d[s] 是否 大于初始值 #include<cstdio> #include<vector> #include<cstring> #include<queue>

最短路(Bellman_Ford) POJ 1860 Currency Exchange

题目传送门 1 /* 2 最短路(Bellman_Ford):求负环的思路,但是反过来用,即找正环 3 详细解释:http://blog.csdn.net/lyy289065406/article/details/6645778 4 */ 5 #include <cstdio> 6 #include <iostream> 7 #include <algorithm> 8 #include <cstring> 9 #include <vector>

poj 1860 Currency Exchange(SPFA)

题目链接:http://poj.org/problem?id=1860 Description Several currency exchange points are working in our city. Let us suppose that each point specializes in two particular currencies and performs exchange operations only with these currencies. There can b

POJ 3259 Wormholes (bellman_ford算法判负环)

Wormholes Time Limit: 2000MS   Memory Limit: 65536K Total Submissions: 32393   Accepted: 11771 Description While exploring his many farms, Farmer John has discovered a number of amazing wormholes. A wormhole is very peculiar because it is a one-way p