套利

套利

题目传送门

前言

本题只有一个点,\(DFS\)应该会被\(T\)飞(我的\(dfs\)死得惨,但不排除能过)

正解:最长路判环(推荐\(SPFA\)


分析

本题可以算是洛谷绿题中蛮简单的那种了(大概也就黄题?

  • 题目条件&我们的任务:
  1. 给出\(N\)个货币汇兑点

  2. 再给出\(M\)对汇率关系

  3. 要求判断从一个汇兑点开始兑换货币,当回到最初汇兑点时是否赚钱了(也可能回不到起点)

结合生活实际很好理解,我们就直接来分析什么情况是\(Yes\),什么情况是\(No\)

很显然,如果存在一个从起点开始的环第二次到达起点时钱变多了,就是\(Yes\)

反之,上述两个条件任意一个不满足则是\(No\)

  • 为什么一定要用最长路?

现实生活中,你肯定希望所有兑换结束后你手里的钱最多啊(不管是亏还是赚),而且有可能当前汇兑点对应多个其他汇兑点,所以采用最长路


代码

因为本来就简单,所以不多说了,直接上\(Code\)

(PS:建议将\(memset\)清空换为\(for\)循环清空,这样可以快一点qwq)

#include <bits/stdc++.h>
using namespace std;
bool flag;
string s,ss;

double c,dis[520010];
int num[520010],vis[520010];
int n,m,cnt,tot,now,head[520010];

struct node {
	int to,net;
	double val;
} e[520010];

inline void add(int u,int v,double w) {
	e[++tot].to=v;
	e[tot].val=w;
	e[tot].net=head[u];
	head[u]=tot;
}

inline bool spfa(int ns) {
	memset(vis,0,sizeof(vis));
	memset(dis,0.0,sizeof(dis));
	memset(num,0,sizeof(num));
	dis[ns]=1.0;
	queue<int> q;
	q.push(ns);
	vis[ns]=1;
	num[ns]=1;
	while(!q.empty()) {
		int x=q.front();
		q.pop();
		vis[x]=0;
		for(register int i=head[x];i;i=e[i].net) {
			int v=e[i].to;
			if(dis[v]<dis[x]*e[i].val) {
				dis[v]=dis[x]*e[i].val;
				if(num[v]==n) return true;
				if(!vis[v]) {
					vis[v]=1;
					num[v]++;
					q.push(v);
				}
			}
		}
	}
	return false;
}

int main() {
	while(scanf("%d",&n)) {
		if(n==0) break;
		now++;
		cnt=0;
		tot=0;
		flag=false;
		map<string,int> name;
		memset(head,0,sizeof(head));
		for(register int i=1;i<=n;i++) {
			cin>>s;
			name[s]=++cnt;
		}
		scanf("%d",&m);
		for(register int i=1;i<=m;i++) {
			cin>>s>>c>>ss;
			add(name[s],name[ss],c);
		}
		printf("Case %d: ",now);
		for(register int i=1;i<=cnt;i++) {
			if(spfa(i)==true&&dis[i]>1.0) {
				puts("Yes");
				flag=true;
				break;
			}
		}
		if(flag==false) puts("No");
	}
	return 0;
} 

posted @ 2020-07-08 21:05  Eleven谦  阅读(27)  评论(0编辑  收藏