POJ1860 货币兑换(单源最短路径)

给定N种货币,某些货币之间可以相互兑换,现在给定一些兑换规则,问能否从某一种货币开始兑换,经过一些中间货币之后,最后兑换回这种货币,并且得到的钱比之前的多。

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

#include <iostream>
#include <cstdio>
#include <algorithm>
using namespace std;

const int N = 105;
const int E = 205;
const double MAX = 999999999;

struct Edge
{
	int beg;
	int end;
	double r, c;
};
Edge edge[E];
double mindis[N];
int n, m, e, fn;
double fv;

void addedge(int beg, int end, double r, double c)
{
	edge[e].beg = beg;
	edge[e].end = end;
	edge[e].r = r;
	edge[e].c = c;
	++e;
}

bool relax(int pe)
{
	double t = (mindis[edge[pe].beg] - edge[pe].c) * edge[pe].r;
	if (t > mindis[edge[pe].end]) 
	{
		mindis[edge[pe].end] = t;
		return true;
	}
	return false;
}

bool bellman_ford()
{
	bool flag;
	for (int i = 0; i < n; ++i) mindis[i] = 0.0;
	mindis[fn] = fv;
	for (int i = 0; i < n - 1; ++i)
	{
		flag = false;
		for (int j = 0; j < e; ++j)
		{
			if (relax(j)) flag = true;
		}
		if (mindis[fn] > fv) return true;
		if (!flag) return false;
	}
	for (int i = 0; i < e; ++i)
	{
		if (relax(i)) return true;
	}
	return false;
}

int main()
{
	int beg, end;
	double r1, r2, c1, c2;
	scanf("%d%d%d%lf", &n, &m, &fn, &fv);
	--fn;
	e = 0;
	for (int i = 0; i < m; ++i)
	{
		scanf("%d%d%lf%lf%lf%lf", &beg, &end, &r1, &c1, &r2, &c2);
		--beg;
		--end;
		addedge(beg, end, r1, c1);
		addedge(end, beg, r2, c2);
	}
	bool ans = bellman_ford();
	if (ans) printf("YES\n");
	else printf("NO\n");
	return 0;
}


你可能感兴趣的:(POJ1860 货币兑换(单源最短路径))