Bellman-Ford算法-POJ1806-JAVA语言描述

POJ1806 

Bellman-Ford算法的反向利用。

可以把初始兑换的货币看成源点,采用bellman-ford进行求解,若可以实现要求,则说明图中存在可以无限增大的环,这个可以通过bellman-ford算法判断环是否存在求出来,若在求解过程中发现已经兑换回原货币,并且钱比之前多,则可以直接退出算法。由于兑换过程中每种货币值必须为非负的,因此可以把所有初始路径长度设置为0,按照兑换方式对边进行松弛。

上代码:


import java.util.Arrays;
import java.util.Scanner;

/*
 * 题意 : 就是套汇的问题,汇率Rab, 增加了一个手续费  Cab 。。。。。。。每次的结果是  (本金 - 手续费) * 汇率,
 * 而且一个人拥有的钱的类型是已知的,拥有的value 钱的个数也是已知的, 问你能不能增值。

当成 每个节点之间都可以来回的图,但是 来回的权值不一样,汇率和手续费不一样,分别保存a到b的和b到a的手续费和汇率
才能是关键,其实也是个水题。。。。。

输入 :
3 2 1 20.0                         //钱种类个数  汇率的个数,拥有第几种钱, 拥有多少钱
1 2 1.00 1.00 1.00 1.00            //钱a, 钱b, rab, cab, rba, cba
2 3 1.10 1.00 1.10 1.00				//rab 为汇率	cab为汇率
 输出:
YES
 * 
 * 
 * */
public class POJ1806 {
    static int n; // 货币种数
    static int m; // 兑换点数量
    static int s; // 持有第 s种 货币
    static double v; // 持有s 货币的本金
    static Edge[] rate;
    static Edge[] commissino;
    static double[] value;
    public static final double EPS = 1E-8;// 10 的 -8 次方

    public static void main(String[] args) {
        // TODO Auto-generated method stub
        Scanner sc = new Scanner(System.in);
        n = sc.nextInt();
        m = sc.nextInt();
        s = sc.nextInt() - 1;// 减去 1 是因为在数组中第一个数的角标为 0
        v = sc.nextDouble();
        int a;
        int b;
        double rab;
        double cab;
        double rba;
        double cba;
        rate = new Edge[m * 2];
        commissino = new Edge[m * 2];
        value = new double[n];

        for (int i = 0; i < 2 * m; i++) {
            a = sc.nextInt() - 1;
            b = sc.nextInt() - 1;
            rab = sc.nextDouble();
            cab = sc.nextDouble();
            rba = sc.nextDouble();
            cba = sc.nextDouble();

            rate[i] = new Edge();
            rate[i].s = a;//这里是a
            rate[i].e = b;
            rate[i].v = rab;
            commissino[i] = new Edge();
            commissino[i].s = a;
            commissino[i].e = b;
            commissino[i].v = cab;

            i++;
            rate[i] = new Edge();
            rate[i].s = b;//跟上面的不一样哦  这里是b
            rate[i].e = a;//
            rate[i].v = rba;
            commissino[i] = new Edge();
            commissino[i].s = b;//
            commissino[i].e = a;//
            commissino[i].v = cba;
        }
        new POJ1806().solve();
    }

    public void solve() {
        if (bellman_ford(s, rate, commissino)) {
            System.out.println("YES");
        } else {
            System.out.println("NO");
        }
    }

    private static boolean bellman_ford(int ss, Edge[] rat, Edge[] com) {
        // TODO Auto-generated method stub
        Arrays.fill(value, 0);// 快速给value数组元素赋值 为0
        value[ss] = v;
        boolean released;
        while (value[ss] <= v + EPS) {
            released = false;
            for (int i = 0; i < 2 * m; i++) {
                if (value[rat[i].e] + EPS < (value[rat[i].s] - com[i].v) * rat[i].v) {//这里反向利用Bellman_Ford算法 来判断是否无限增大
                    value[rat[i].e] = (value[rat[i].s] - com[i].v) * rat[i].v;
                    released = true;
                    //System.out.println(Arrays.toString(value));
                }
            }
            if (!released) {
                //System.out.println(true);
                return value[ss] > v + EPS;
            }
        }
        //System.out.println(value[s]);
        return true;
    }

}

class Edge {
    int s;
    int e;
    double v;
}

    原文作者:Bellman - ford算法
    原文地址: https://blog.csdn.net/Divide_/article/details/51292612
    本文转自网络文章,转载此文章仅为分享知识,如有侵权,请联系博主进行删除。
点赞