暑假-最短路(Bellman-ford、spfa)-A - Arbitrage

题意:给你一些货币,和货币之间的转换率。

问:是否存在某种货币经过数次转换回到原本的货币之后有利润

(即求从起点出发再回到起点时候是否有钱赚,即回路问题)

方法:Floyd,Bellman-ford算法

注意:数组是double型,将字符串转换为对于的号码,

初始化自身与自身转换的汇率为1. 货币之间的转换为乘法运算

Floyd算法:

#include<iostream>
#include<cstring>
using namespace std;
const int MAXM = 35;
double map[MAXM][MAXM];
//对应的邻接表
char name[MAXM][100];
//货币名称
double dist[MAXM][MAXM]; 
//floyd后的每个点到其他点的最大值
int n, m;
//货币数,边数
int getname(char s[])//货币名称对应的号码
{
	for (int i = 0; i < n; i++)
	{
		if (strcmp(name[i], s) == 0)
		{
			return i;
		}
	}
}
void Floyd()
{
	memset(dist, 0, sizeof(dist));
	int v, w, k;
	for (v = 0; v < n; v++)
	{
		for (w = 0; w < n; w++)
		{
			dist[v][w] = map[v][w];//初始化
		}
	}
	//Floyd算法,k为中间转换点,v为开始点,w为结束点
	for (k = 0; k < n; k++)
	{
		for (v = 0; v < n; v++)
		{
			for (w = 0; w < n; w++)
			{
				if (dist[v][w] < dist[v][k] * dist[k][w])
				{//若果v通过k间接到达w的值比v直接到w的值要大的话
					//将算法的'+'改成'*','>'改成'<'
					dist[v][w] = dist[v][k] * dist[k][w];
				}
			}
		}
	}
}
int main()
{
	int ans = 0,u,v;
	while (cin >> n)
	{
		if (n == 0)
		{
			break;
		}
		bool k = false;
		memset(map, 0, sizeof(dist));
		for (int i = 0; i < n; i++)
		{
			cin >> name[i];
			map[i][i] = 1;//初始化自己和自己换的汇率为1.
		}
		cin >> m;
		char name1[100];
		double val;
		for (int i = 0; i < m; i++)//构建邻接表
		{
			cin >> name1;
			u = getname(name1);
			cin >> val;
			cin >> name1;
			v = getname(name1);
			map[u][v] = val;
		}
		Floyd();
		for (int i = 0; i < n; i++)
		{
			if (dist[i][i]>1)
			{//如果通过一个回路之后比原来赚了
				k = true;
				break;
			}
		}
		cout << "Case " << ++ans << ": "; 
		if (k)
		{
			cout << "Yes" << endl;
		}
		else
		{
			cout << "No" << endl;
		}
	}
	return 0;
}

Bellman-ford算法:

#include<iostream>
#include<cstring>
using namespace std;
const int MAXM = 35;
const int MAXN = 1000;
//边数的上限为30*29
struct Node
{
	int v;
	int u;
	double w;
};//邻接表直接储存边的信息【间接的比较费时和空间】
Node edges[MAXN];
char name[MAXM][100];
//货币名字
bool k;
int n, m;
//点数,边数
double dist[MAXN];
//从某个顶点出发到其他顶点的值
int getname(char s[])//货币对应的编号
{
	for (int i = 0; i < n; i++)
	{
		if (strcmp(name[i], s) == 0)
		{
			return i;
		}
	}
}
void Bellman(int v0)
{
	memset(dist, 0, sizeof(dist));
	dist[v0] = 1;//初始化自身直接的转换的汇率为1
	for (int i = 0; i < n; i++)//Bellman-ford算法
	{
		for (int j = 0; j < m; j++)
		{
			if (dist[edges[j].u] && dist[edges[j].u] * edges[j].w > dist[edges[j].v])
			{
				dist[edges[j].v] = dist[edges[j].u] * edges[j].w;
			}
		}
	}
	if (dist[v0]>1)//v0到v0的值。果然大于1说明有利润
	{
		k = true;
	}
}
int main()
{
	int ans = 0;
	while (cin >> n)
	{
		k = false;
		if (!n)
		{
			break;
		}
		for (int i = 0; i < n; i++)
		{
			cin >> name[i];
		}
		cin >> m;
		char name1[100];
		double val;
		for (int i = 0; i < m; i++)//构建邻接表
		{
			cin >> name1;
			edges[i].u = getname(name1);
			cin >> val;
			edges[i].w = val;
			cin >> name1;
			edges[i].v = getname(name1);
		}
		for (int i = 0; i < n; i++)
		{
			Bellman(i);//以所有顶点为起点出发求到其他点的值
			if (k)
			{
				break;
			}
		}
		cout << "Case " << ++ans << ": ";
		if (k)
		{
			cout << "Yes" << endl;
		}
		else
		{
			cout << "No" << endl;
		}
	}
	return 0;
}
    原文作者:Bellman - ford算法
    原文地址: https://blog.csdn.net/slime_kirito/article/details/47682495
    本文转自网络文章,转载此文章仅为分享知识,如有侵权,请联系博主进行删除。
点赞