题目链接:http://acm.hust.edu.cn/vjudge/contest/view.action?cid=66569#problem/I
题意:Arbitrage,意思为套利交易:有多个汇率兑换点,问是否存在这样一中情况:把某种货币经过若干转换后在换回本币,使本币的数量增加?
题解:这题很显然就是正环存在问题,只是,我们并不知道,哪些点包含于正环之中,那么我们枚举就行了,顺便增加一个标志数组,看是改点是否更新过,可以大大减少不必要的运算,正环存在的条件是:每个点的更新次数不会超过N,而我前面那几题写的是cnt[i]>=N,居然都过了!!此题WA了好几次,才AC,原来是cnt数组写错了,傻逼了,震的傻逼了。
代码:
#include<iostream>
#include<cstdio>
#include<cstring>
#include<algorithm>
#include<vector>
#include<map>
#include<queue>
#include<string>
#define INF 0x7fffffff
using namespace std;
map<string,int> mp;
int n,m,Map[33][33],vis[33],vis2[33],cnt[33];
double R[33][33],num[33],eps=1e-10;
int bfs(int st){
memset(vis,0,sizeof(vis));
memset(num,0,sizeof(num));
memset(cnt,0,sizeof(cnt));
queue<int> Q;
Q.push(st);vis[st]=1;num[st]=1;vis2[st]=1;cnt[st]++;
while(!Q.empty()){
int tp=Q.front();Q.pop();vis[tp]=0;
if(cnt[tp]>n) return 1;//环存在条件,这里不喊=号!!
for(int i=0;i<n;i++) if(Map[tp][i]){
double t=num[tp]*R[tp][i];
if(t-num[i]<eps) continue;
num[i]=t;
if(!vis[i]) vis[i]=1,Q.push(i),cnt[i]++,vis2[i]=1;
}
}
return 0;
}
int main(){
//freopen("D:in.txt","r",stdin);
int kase=1;
while(cin>>n && n){
mp.clear();
string s;
for(int i=0;i<n;i++) {
cin>>s;
mp[s]=i;
}
memset(Map,0,sizeof(Map));
cin>>m;
string ss;double t;
for(int i=0;i<m;i++){
cin>>s>>t>>ss;
int a=mp[s],b=mp[ss];
Map[a][b]=1;
R[a][b]=t;
}
int op=0;
memset(vis2,0,sizeof(vis2));//某点是否更新过的标识
for(int i=0;i<n;i++) if(!vis2[i] && bfs(i)) {op=1;break;}
if(op) printf("Case %d: Yes\n",kase);
else printf("Case %d: No\n",kase);
kase++;
}
return 0;
}