zoukankan      html  css  js  c++  java
  • poj 1860 最短路—Bellman-Ford算法

    有多种汇币,汇币之间可以交换,这需要手续费,当你用100A币
    交换B币时,A到B的汇率是29.75,手续费是0.39,那么你可以得到
    (100 - 0.39) * 29.75 = 2963.3975 B币。问s币的金额经过交换最终
    得到的s币金额数能否增加
    货币的交换是可以重复多次的,所以我们需要找出是否存在
    正权回路,且最后得到的s金额是增加的
    怎么找正权回路呢?(正权回路:在这一回路上,顶点的权值能不断增加即能一直进行松弛)

    关键在于反向利用Bellman-Ford算法

    单源最短路径算法,因为题目可能存在负边,所以用Bellman Ford算法,
    原始Bellman Ford可以用来求负环,这题需要改进一下用来求正环

    一种货币就是图上的一个点
    一个“兑换点”就是图上两种货币之间的一个兑换环,相当于“兑换方式”M的个数,是双边
    唯一值得注意的是权值,当拥有货币A的数量为V时,A到A的权值为K,即没有兑换
    而A到B的权值为(V-Cab)*Rab
    本题是“求最大路径”,之所以被归类为“求最小路径”是因为本题题恰恰
    与bellman-Ford算法的松弛条件相反,求的是能无限松弛的最大正权路径,
    但是依然能够利用bellman-Ford的思想去解题。
    因此初始化d(S)=V 而源点到其他店的距离(权值)初始化为无穷小(0),
    当s到其他某点的距离能不断变大时,说明存在最大路径.
    以上copy自kuangbin大神的分析。

    #include<iostream>
    #include<cstdio>
    #include<cstring>
    #include<algorithm>
    #include<cmath>
    #include<stack>
    #include<map>
    #include<vector>
    #include<queue>
    using namespace std;
    #define mp make_pair
    #define x first
    #define y second
    const int INF=0x3f3f3f3f;
    const int N=111;
    typedef pair<int,int>pii;
    struct edge
    {
        int u,v;
        double c,m;
        edge(int u,int v,double c,double m):u(u),v(v),c(c),m(m){}
    };
    vector<edge>e;
    double d[N];
    int n,m,S;
    double V;
    bool BF()
    {
        for(int i=1;i<=n;i++)d[i]=0;
        d[S]=V;
        for(int i=1;i<n;i++){
            bool flag=0;
            for(int j=0;j<e.size();j++){
                int u=e[j].u,v=e[j].v;
                double c=e[j].c,m=e[j].m;
                if(d[v]<(d[u]-m)*c){
                    flag=1;
                    d[v]=(d[u]-m)*c;
                }
            }
            if(!flag)return false;
        }
        for(int j=0;j<e.size();j++){
            int u=e[j].u,v=e[j].v;
            double c=e[j].c,m=e[j].m;
            if(d[v]<(d[u]-m)*c){
                return true;
            }
        }
        return false;
    }
    int main()
    {
        scanf("%d%d%d%lf",&n,&m,&S,&V);
        int a,b;
        double c1,c2,m1,m2;
        for(int i=0;i<m;i++){
            scanf("%d%d%lf%lf%lf%lf",&a,&b,&c1,&m1,&c2,&m2);
            e.push_back(edge(a,b,c1,m1));
            e.push_back(edge(b,a,c2,m2));
        }
        if(BF())printf("YES
    ");
        else printf("NO
    ");
        return 0;
    }
  • 相关阅读:
    牛客网 二叉树的镜像 JAVA
    牛客网 反转链表 JAVA
    牛客网 调整数组顺序使奇数位于偶数前面 JAVA
    Integer to Roman LeetCode Java
    Valid Number leetcode java
    Longest Common Prefix
    Wildcard Matching leetcode java
    Regular Expression Matching
    Longest Palindromic Substring
    Add Binary LeetCode Java
  • 原文地址:https://www.cnblogs.com/01world/p/5651196.html
Copyright © 2011-2022 走看看