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;
}


你可能感兴趣的:(数据结构与算法)