题目大意
有多种汇币,汇币之间可以交换,这需要手续费,当你用100A币交换B币时,A到B的汇率是29.75,手续费是0.39,那么你可以得到(100 - 0.39) * 29.75 = 2963.3975 B币。问s币的金额经过交换最终得到的s币金额数能否增加
算法思想:最短路变形,spfa变形可过。
提示:关键是找出正环,在此回路上来回跑,货币金额就一直涨。
#include<iostream>
#include<algorithm>
#include<cmath>
#include<cstdio>
using namespace std;
int n,m,pos,a,b,ans;
double sv,xx,yy,x2,y2,dis[205];
int num,v[100001],q[10005],numb[10005];
bool flag,vis[205];
struct mc
{
int x,y,ne;
double rat,mon;
} e[100001];
void put(int x,int y,double rat,double mon) //rat 汇率;mon 手续费;
{
num++;
e[num].x=x;
e[num].y=y;
e[num].rat=rat;
e[num].mon=mon;
e[num].ne=v[x];
v[x]=num;
}
int spfa(int pos) //pos 初始金额;
{
for (int i=1;i<=n;i++)
dis[i]=-1;
dis[pos]=sv;
vis[pos]=1;
q[1]=pos;
int h=0,w=1;
while (h!=w)
{
h++;
int x=q[h];
for (int i=v[x];i;i=e[i].ne)
{
int y=e[i].y;
flag=0;
if ((dis[x]-e[i].mon)*e[i].rat>dis[y]) //dis存储当前最大金额;
{
dis[y]=(dis[x]-e[i].mon)*e[i].rat;
if (!vis[y])
{
w++;
q[w]=y;
vis[y]=1;
numb[y]++;
if (numb[y]>n) return 1; //某点经过次数达到一定值时可判断有正权回路,返回true;
}
}
}
vis[x]=0;
}
if (dis[pos]>sv) return 1; //钱变多,返回true;
else return 0; //前变少,返回false;
}
int main()
{
scanf("%d%d%d%lf",&n,&m,&pos,&sv);
for (int i=1;i<=m;i++)
{
scanf("%d%d%lf%lf%lf%lf",&a,&b,&xx,&yy,&x2,&y2);
put(a,b,xx,yy);
put(b,a,x2,y2);
}
ans=spfa(pos);
if (ans) printf("YES");
else printf("NO");
}