这题和POJ2240是两道很经典的题目,这两道题目是求最大路径。本题是反向利用Bellman-Ford算法,求能无限松弛的最大路径,因此松弛操作的次数也不一定是n-1次(n是货币种类数),只要某一次松弛操作时,sum[s]的值能比输入的钱的数量大就可以,松弛操作的次数可能大于n-1次,也可能小于n-1次,在用Bellman-Ford算法求最短路径时,每次松弛可以设置一个标志,初值为false,如果有边可以更新,则置为true,当在某次松弛操作没法更新时,说明已经找到了最短路径长度,如果再更新,便会使得求得的距离比最短路径长度更大,此时flag值为false,直接退出,求出了最短路径。类似的,在本题中,每次松弛操作时都设置一个标志flag,初值均为false,每次松弛操作时,如果存在某条边使得货币总数增加,则置flag值为true,否则置为false,当为false时,直接退出,没有满足要求的最大路径。
#include <iostream>
#include <cstdio>
#include <cstring>
#define eps 1e-8
using namespace std;
const int maxn=102;
int n,m,s;
double money,sum[maxn]; //sum[i]为当前的钱在第i种货币下的价值
struct Edge
{
int u;
int v;
double r; //汇率
double c; //手续费
}edge[2*maxn];
bool Bellman_Ford(int num)
{
int i;
bool flag;
sum[s]=money;
while(sum[s]<money+eps)
{
flag=false;
for(i=0;i<num;i++)
if(sum[edge[i].v]<(sum[edge[i].u]-edge[i].c)*edge[i].r)
{
sum[edge[i].v]=(sum[edge[i].u]-edge[i].c)*edge[i].r;
flag=true;
}
if(!flag) //没有正权值的环使得资金增加,直接返回
return false;
}
return true;
}
int main()
{
int i,u,v,num;
double ru,cu,rv,cv;
bool flag;
scanf("%d%d%d%lf",&n,&m,&s,&money);
num=0;
for(i=0;i<m;i++)
{
scanf("%d%d%lf%lf%lf%lf",&u,&v,&ru,&cu,&rv,&cv);
edge[num].u=u;
edge[num].v=v;
edge[num].r=ru;
edge[num++].c=cu;
edge[num].u=v;
edge[num].v=u;
edge[num].r=rv;
edge[num++].c=cv;
}
flag=false;
memset(sum,0,sizeof(sum));
flag=Bellman_Ford(num);
if(flag)
printf("YES\n");
else
printf("NO\n");
return 0;
}