【POJ2240】Arbitrage【负环】

题目大意:

题目链接:http://poj.org/problem?id=2240
求一些货币互相兑换后能否增值。


思路:

负环半模板题。不能再这样水下去了

很明显的,把货币之间的利率转换成一个相乘的最短路问题,那么如果从一个点开始,走了一圈回到原来那个点时,钱数上涨了,那么久说明增值了。
这道题的输入是比较奇怪的,可以使用mapmap来把字符串转换成数字,然后跑正常的负环。


代码:

#include <cstdio>
#include <cstring> 
#include <map>
#include <iostream>
#include <queue>
#include <string>
using namespace std;

const int N=35; 
const int M=N*N;
const double Inf=1000000000000000000.0;
int n,m,head[N],tot,CNT,cnt[N];
double dis[N];
bool vis[N];
string s1,s2;

map<string,int> Name;

struct edge
{
	int next,to;
	double dis;
}e[M];

void add(int from,int to,double dis)
{
	e[++tot].to=to;
	e[tot].dis=dis;
	e[tot].next=head[from];
	head[from]=tot;
}

bool spfa()
{
	for (int i=1;i<=n;i++)
		dis[i]=0,vis[i]=0,cnt[i]=0;
	queue<int> q;
	q.push(1);
	dis[1]=1.0;
	vis[1]=1;
	cnt[1]=1;
	while (q.size())
	{
		int u=q.front(),v;
		q.pop();
		vis[u]=0;
		for (int i=head[u];~i;i=e[i].next)
		{
			v=e[i].to;
			if (dis[v]<dis[u]*e[i].dis)
			{
				dis[v]=dis[u]*e[i].dis;
				cnt[v]=cnt[u]+1;
				if (cnt[v]>n) return 1;
				if (!vis[v])
				{
					vis[v]=1;
					q.push(v);
				}
			}
		}
	}
	return 0;
}

int main()
{
	while (scanf("%d",&n)&&n)
	{
		memset(head,-1,sizeof(head));
		memset(e,0,sizeof(e)); 
		Name.clear();
		tot=0;
		for (int i=1;i<=n;i++)
		{
			//scanf("%s",&s1);
			cin>>s1;
			Name[s1]=i;  //记录编号 
		}
		scanf("%d",&m);
		for (int i=1;i<=m;i++)
		{
			double x;
			//scanf("%s%d%s",&s1,&x,&s2);
			cin>>s1>>x>>s2;
			add(Name[s1],Name[s2],x);  //取编号来连边
		}
		printf("Case %d: ",++CNT);
		if (spfa()) printf("Yes
");
			else printf("No
");
	}
}
原文地址:https://www.cnblogs.com/hello-tomorrow/p/11998308.html