题目链接:http://poj.org/problem?id=1860
题意:首先给出四个数n,m,s,v,分别表示n种货币,m个兑换关系,s源货币,源货币的本金v
然后给出m行,每行给出6个数beg,end,r1,c1,r2,c2,分别表示beg和end货币兑换的比率和手续费,end和beg货币兑换的比率和手续费
。问能否通过货币兑换使手里的源货币依然是第s中货币,并且本金增多。
思路:感觉如果不是对最短路算法很熟悉的话,这道题很不好做。实际上这道题是Bellman-Ford的变形,求最长路径,利用Bellman-Ford
算法的思想,判断是否存在正环就可以了。具体代码实现如下。
(顺便补充一句,最近刚接触Bellman-Ford算法,感觉像是在Dijsktra算法的基础上增加一层循环判断是否存在负环就可以了,另外,从效率上
来看,个人感觉无负权图优先考虑Dijsktra,带负权图优先考虑SPFA,似乎Bellman-Ford用的地方比较少)
#include<iostream> #include<cstdio> #include<cstring> #include<algorithm> #include<cmath> #include<queue> using namespace std; const int INF=0x3f3f3f3f; const int maxn=505; int n,m,s; double v; double dis[maxn]; int e; struct Edge{ int u; int v; double r; double c; }edge[maxn]; void addEdge(int u,int v,double r,double c){ edge[e].u=u; edge[e].v=v; edge[e].r=r; edge[e].c=c; e++; } bool relax(int j){ if(dis[edge[j].v]<(dis[edge[j].u]-edge[j].c)*edge[j].r){ dis[edge[j].v]=(dis[edge[j].u]-edge[j].c)*edge[j].r; return true; } return false; } bool Bellman_Ford(){ memset(dis,0,sizeof(dis)); dis[s]=v; bool flag; for(int i=1;i<n;i++){ flag=false; for(int j=0;j<e;j++){ if(relax(j)) flag=true; } if(dis[s]>v) return true; if(!flag) return false; } for(int k=0;k<e;k++){ if(relax(k)) return true; } return false; } int main(){ #ifndef ONLINE_JUDGE freopen("test.in","r",stdin); freopen("test.out","w",stdout); #endif while(~scanf("%d%d%d%lf",&n,&m,&s,&v)){ e=0,s--; int beg,end; double r1,c1,r2,c2; for(int i=0;i<m;i++){ scanf("%d%d%lf%lf%lf%lf",&beg,&end,&r1,&c1,&r2,&c2); beg--,end--; addEdge(beg,end,r1,c1); addEdge(end,beg,r2,c2); } bool ans=Bellman_Ford(); if(ans==1) puts("YES\n"); else puts("NO\n"); } return 0; }