题意:给你一些货币,和货币之间的转换率。
问:是否存在某种货币经过数次转换回到原本的货币之后有利润
(即求从起点出发再回到起点时候是否有钱赚,即回路问题)
方法: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;
}