题目链接: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;
}