poj-2240 Bellman-ford

题意:

已知n种货币,以及m种货币汇率及方式,问能否通过货币转换,使得财富增加。


题目链接:Arbitrage


解题思路:

目测是一条不错的生财之道~~~(打住)


财富增加的话肯定是以同种货币作比较,否则没有意义,因此题意大致可以变成在一个n个顶点的图中能否找到一个正权环,这里的正权环指财富增加,很明显可用Bellman-ford 算法(专门解决存在环的最短路径问题)。


Bellman-ford 算法:一个具有n个顶点的图如果不存在环,则从顶点x,到顶点y,最多经过n-1条边(要考虑连通性,每个顶点最多经过 1 次),因此 x 到 y 的最短路 最多经过 n – 1 次松弛操作(就是更新长度)就应该出现,如果第 n 次松弛还可以得到最优,那么这个图就肯定是存在环了(直接用Dijkstra 就无法得到最优的,环的存在会影响最优解是否存在)。


这里给的顶点时货币的英文名,为了方便简洁,用map 将货币名 与 编号一一对应


此题有多种解法,注意到顶点最大为30(限制很小,不愧是模板练习题),可用Floyd算法求出整个图的最短路,注意此处并不是真正的最短路,但通过插点,即 i -> j 能否改成 i -> k -> j 的路,就会把环给考虑至少一次,那么对应的 path[i][i] 也就是本金肯定是增加的(相对于初值),为了方便,将本金设为 1 .


代码;

Bellman_ford 实现:

#include<iostream>
#include<cstdio>
#include<queue>
#include<map>
#include<string>
using namespace std;
#define Max 900
int n, m, k;
double disit[Max];
struct P {
	int s;
	int e;
	double t;
}dp[Max];
bool B_floyd(int u)
{
	memset(disit, 0, sizeof(disit));
	disit[u] = 1;
	for (int i = 0; i < n - 1; i++)
	{
		for (int j = 0; j < k; j++)
		{
			if (disit[dp[j].e] < (disit[dp[j].s] * dp[j].t))
			{
				disit[dp[j].e] = disit[dp[j].s] * dp[j].t;
			}
		}
	}
	for (int i = 0; i < k; i++)
	{
		if (disit[dp[i].e] < (disit[dp[i].s] * dp[i].t))
		{
			return true;
		}
	}
	return false;
}
int main()
{
	int nn = 1;
	string strs, strs1;
	double rab;
	while (~scanf("%d", &n) && n != 0)
	{
		k = 0;
		memset(disit, 0, sizeof(disit));
		map<string, int> mp;
		cin.get();
		for (int i = 0; i < n; i++)
		{
			cin >> strs;
			mp[strs] = i;
		}
		scanf("%d", &m);
		cin.get();
		for (int i = 0; i < m; i++)
		{
			cin >> strs >> rab >> strs1;
			dp[k].e = mp[strs1];
			dp[k].s = mp[strs];
			dp[k++].t = rab;
		}
		int flag = 0;
		for (int i = 0; i < n; i++)
		{
			if (B_floyd(i))
			{
				cout <<"Case "<<nn++<< ": Yes" << endl;
				flag = 1;
				break;
			}
		}
		if (!flag)
			cout<<"Case "<<nn++<< ": No" << endl;
		cout << endl;
	}
	return 0;
}

另一个代码:

#include<iostream>
#include<cstdio>
#include<queue>
#include<map>
#include<string>
using namespace std;
#define Max 100
int n, m;
int visit[Max];
double disit[Max];
double dp[Max][Max];
bool B_floyd(int u)
{
	queue<int>q;
	disit[u] = 1;
	q.push(u);
	while (!q.empty())
	{
		int temp = q.front();
		visit[temp] = 0;
		q.pop();
		for (int i = 0; i < n; i++)
		{
			if (dp[temp][i] != 0)
			{
				if (disit[i] < (disit[temp] * dp[temp][i]))
				{
					disit[i] = (disit[temp] * dp[temp][i]);
					if (disit[u] > 1)
					{
						return true;
					}	
					if (!visit[i])
					{
						visit[i] = 1;
						q.push(i);
					}
				}
			}
		}
	}
	return false;
}
int main()
{
	string strs, strs1;
	int nn = 1;
	double rab;
	while (~scanf("%d", &n) && n != 0)
	{
		map<string, int> mp;
		cin.get();
		memset(dp, 0, sizeof(dp));
		for (int i = 0; i < n; i++)
		{
			cin >> strs;
			mp[strs] = i;
		}
		scanf("%d", &m);
		cin.get();
		for (int i = 0; i < m; i++)
		{
			cin >> strs >> rab >> strs1;
			dp[mp[strs]][mp[strs1]] = rab;
		}
		int flag = 0;
		for (int i = 0; i < n; i++)
		{
			memset(visit, 0, sizeof(visit));
			memset(disit, 0, sizeof(disit));
			if (B_floyd(i))
			{
				cout << "Case " << nn++ << ": Yes" << endl << endl;
				flag = 1;
				break;
			}
		}
		if(!flag)
			cout << "Case " << nn++ << ": No" << endl << endl;
	}
	return 0;
}

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