题意:有n个国家货币,给出m种两个国家之间的货币兑换率,求是否可以盈利.......
思路:其实就是看国家货币兑换间是否存在一个环,使得从v点出发时,dis[v]=1,经过环回到v点时,dis[v]>1.......当然,路径是单向的。这个题目的松弛是:dis[i]<dis[v]*map[v][i],只单单spfa来说,要判断存在一个正环,那么就是某个点被历遍>=n+1次,从而判断这个环不存在“最大路”.....但是,就这题目而已,我们不需要判断最大路是否存在,我们只需要判断,是否可以盈利。可以盈利的话,那么从某个点p出发,经过一个环,回到点p,通过松弛,dis[p]>1,说明可以盈利,否则就是不能。那么可以使用数组进行标记,每次一个点可以松弛(就是满足dis[i]<dis[v]*map[v][i]),那么先更新这个点的最大值,然后判断这个点是否在队列里面,在的话,就不需要压入队列,否则压入队列......一个点出队列的时候,它相应的标记数要清零.......
#include<iostream> #include<cstdio> #include<cstring> #include<vector> #include<queue> using namespace std; struct node { int e; double d; }; char t[50][100],s[1000][100],s1[1000][100],vist[1000]; int n,m,flg; double dis[100],x[1000]; vector<node>vet[1000]; void spfa(int v) { for(int i=0;i<=n;i++) dis[i]=0; dis[v]=1.0; queue<int>q; q.push(v); vist[v]=1; while(!q.empty()) { int u=q.front(); q.pop(); vist[u]=0; for(int i=0;i<vet[u].size();i++) { node p=vet[u][i]; //printf("%d %d %.3lf ",u,p.e,p.d); if(dis[p.e]<dis[u]*p.d) { dis[p.e]=dis[u]*p.d; //vist[p.e]=1; if(vist[p.e]==0) q.push(p.e); vist[p.e]=1; if(dis[v]>1.0) { flg=1; return; } } } } } int main() { int text=0; while(scanf("%d",&n)>0&&n) { for(int i=0;i<n;i++) scanf("%s",t[i]); for(int i=0;i<=n;i++) vet[i].clear(); scanf("%d",&m); for(int i=0;i<m;i++) { scanf("%s %lf %s",s[i],&x[i],s1[i]); int xx,yy; for(int j=0;j<n;j++) { if(strcmp(s[i],t[j])==0) { xx=j; } if(strcmp(s1[i],t[j])==0) { yy=j; } } node p; p.e=yy; p.d=x[i]; vet[xx].push_back(p); //p.e=xx; //vet[yy].push_back(p); } int i; printf("Case %d: ",++text); for(i=0;i<n;i++) { flg=0; memset(vist,0,sizeof(vist)); spfa(i); if(flg==1) { printf("Yes "); break; } } if(i==n) printf("No "); } return 0; }