题目链接:
https://www.luogu.org/problem/P1931
类似题目:
https://blog.csdn.net/aiwo1376301646/article/details/100583424
思路:
1:方向:最长路的变形问题
2:把汇率表抽象成一个有向图,每个货币是一个结点,每条边上的权值就是汇率
3:无法套利的情况分两种:
1:没有环,即最后无法回到该种货币
2:有环,但是没有利率之积大于1的环
4:核心思想及注意事项:满足题意可以套利的情况需要满足两个条件:
1:有环
2:有利率之积大于1的环
思考我们判断是否有环的方法是,用一个数组times存每一个节点入队的次数,如果有环,那么同一个节点入队的次数将大于等于节点总个数即n个,又因为要使一个节点n次及以上入队,那么必须满足
if(d[v]<d[now]*e[now][i].second)
也就说明了,经过这一圈的转换,比原来的值大,(只有比原来的值大,才可以执行if条件里的代码,才可以实现times[v]>=n这一行代码)这也就说明了,是可以套利的,环的利率之积大于1,因此只要可以形成环,那么就一定满足可以套利(就是说,有环和环的利率之积大于1,这两个条件是相辅相成的,只要有环,那么就一定满足环的利率之积大于1,只有利率之积大于1,才可以形成环)
5:这道题目还应该特别注意,一定要初始化,因为涉及多组数据,如果不想初始化,那么就把要用到的结构写在main函数中,但缺点是调用函数时要做为参数传进去
#include <bits/stdc++.h>
using namespace std;
const int maxn=31;
vector<pair<int,double> >e[maxn];
int n,m,ing[maxn],cnt,num=1,times[maxn];
double d[maxn],c;
string a,b;
map<string,int>ma;
inline bool spfa(int s)
{
memset(ing,0,sizeof(ing));
memset(d,0,sizeof(d));
memset(times,0,sizeof(times));
queue<int>q;
q.push(s);
times[s]++;
d[s]=1;
ing[s]=1;
while(!q.empty())
{
int now=q.front();
q.pop();
ing[now]=0;
for(int i=0;i<e[now].size();i++)
{
int v=e[now][i].first;
if(d[v]<d[now]*e[now][i].second)
{
d[v]=d[now]*e[now][i].second;
if(ing[v])
continue;
q.push(v);
times[v]++;
if(times[v]>=n)
return true;
ing[v]=1;
}
}
}
return false;
}
int main()
{
ios::sync_with_stdio(0);
while(cin>>n&&n)
{
cnt=1;
ma.clear();
for(int i=1;i<=n;i++)
{
e[i].clear();
}
for(int i=1;i<=n;i++)
{
cin>>a;
ma[a]=cnt++;
}
cin>>m;
for(int i=1;i<=m;i++)
{
cin>>a>>c>>b;
e[ma[a]].push_back(make_pair(ma[b],c));
}
bool flag=true;
for(int i=1;i<=n;i++)
{
if(spfa(i))
{
cout<<"Case "<<num++<<": Yes"<<endl;
flag=false;
break;
}
}
if(flag)
cout<<"Case "<<num++<<": No"<<endl;
}
return 0;
}