题意:给定若干种货币之间兑换的汇率和手续费,初始给定一种货币和价值,问能不能通过一系列兑换最后回到初始货币种类时价值上升
分析:每种货币代表一个点,给货币兑换的关系看作两点的边建图,跑一遍SPFA判正环,若存在正环则必有解使得最终货币价值上升,为什么,因为按照正环兑换一遍价值就会上升,那么一定可以通过有限次正环使得价值大到回到起点的时候价值依然大于初始值;
代码:
#include<queue>
#include<cstdio>
#include<cstring>
#include<iostream>
using namespace std;
const int N = 100+10;
const int INF = 0X3F3F3F3F3F;
struct node{
int to,nxt;
double rate,com;
node(){}
node(int _to,int _nxt,double _rate,double _com):to(_to),nxt(_nxt),rate(_rate),com(_com){}
}e[N<<1];
int head[N],tot;
void add(int u,int v,double r,double c){
e[tot]=node(v,head[u],r,c);
head[u]=tot++;
}
int n,m,vis[N],out[N],S;
double dis[N],w;
bool SPFA(){
for(int i=1;i<=n;i++) dis[i]=-INF,vis[i]=out[i]=0;
vis[S]=1,out[S]=1,dis[S]=w;
queue<int>que;
que.push(S);
while(!que.empty()){
int u=que.front(); que.pop(); vis[u]=0;
for(int i=head[u];i!=-1;i=e[i].nxt){
int v=e[i].to;
double r=e[i].rate,c=e[i].com;
if(dis[v]<(dis[u]-c)*r){
dis[v]=(dis[u]-c)*r;
if(!vis[v]){
vis[v]=1;
que.push(v);
if(++out[v]>n) return true;
}
}
if(dis[S]>w) return true;
}
}
return false;
}
int main()
{
memset(head,-1,sizeof(head)),tot=0;
scanf("%d%d%d%lf",&n,&m,&S,&w);
for(int i=0;i<m;i++){
int u,v;
double r1,c1,r2,c2;
scanf("%d%d%lf%lf%lf%lf",&u,&v,&r1,&c1,&r2,&c2);
add(u,v,r1,c1);
add(v,u,r2,c2);
}
if(SPFA()) printf("YES");
else printf("NO");
}