套利
前言
本题只有一个点,(DFS)应该会被(T)飞(我的(dfs)死得惨,但不排除能过)
正解:最长路判环(推荐(SPFA))
分析
本题可以算是洛谷绿题中蛮简单的那种了(大概也就黄题?)
- 题目条件&我们的任务:
-
给出(N)个货币汇兑点
-
再给出(M)对汇率关系
-
要求判断从一个汇兑点开始兑换货币,当回到最初汇兑点时是否赚钱了(也可能回不到起点)
结合生活实际很好理解,我们就直接来分析什么情况是(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;
}