做完后梳理下这道题。
首先,题意是给我们n种货币,m个货币兑换点,然后有转换规则.问你最后经过一连串转换后,回到起点,你手上的这种货币数量有没有增多
我们将它转化为一个图的问题.
那么就是把n种货币看成n个点,把m个货币兑换点看成m条边,但是注意这条边上存的是转换规则,因为边的权值应该是转换后的货币量,我们一开始不可能知道。
那么,我们再看一下这个提问,问你回到起点后的数量,首先,我们边可以将它看成有向边,点A转换为点B的兑换规则看成一条A-B的有向边,那么B-A的兑换规则就是一条B-A的有向边。根据提问,我们最后能要回到起点,说明图中肯定存在环,而且我们回到起点后,数量要增长,那么就肯定存在一条正环。我们只需要一直判断dis[s],也就是到原点的权值是不是大于开始的v了,如果大于了,那么就说明存在正环。
注意点:我们一开始的dis[s]应该等于我们原来的数量v,这样才能通过边上的转换规则转换得到边上的权值.
#include<iostream>
#include<stdio.h>
#include<queue>
#include<algorithm>
#include<math.h>
#include<stack>
#include<map>
#include<limits.h>
#include<vector>
#include<string.h>
using namespace std;
typedef long long LL;
typedef unsigned long long ULL;
typedef pair<int,int> pii;
const int N = 1e7;
const int M = 1e5+7;
#define INF 1e7+5
#define INM INT_MIN
#define pb(a) push_back(a)
#define mk(a,b) make_pair(a,b)
#define dbg(x) cout << "now this num is " << x << endl;
#define sd(a) scanf("%d",&a)
#define sld(a) scanf("%lld",&a)
#define sdd(a,b) scanf("%d %d",&a,&b)
#define sddd(a,b,c) scanf("%d %d %d",&a,&b,&c)
#define pr(a) printf("%d\n",a)
#define plr(a) printf("%lld\n",a)
#define pr_(a) printf("%d ",a)
#define _pr(a) printf(" %d",a)
int vis[105],n,m,s;
double dis[105],v;
struct Node
{
int to;
double a1,b1;//存转换规则,只存A-B的,因为看成有向边
};
vector<Node> G[105];
bool spfa(int x)
{
memset(vis,0,sizeof(vis));
vis[x] = 1;
for(int i=1;i<=n;++i) dis[i] = 0;//这里应该是找最大路
dis[x] = v;
queue<int> Q;
Q.push(x);
while(!Q.empty())
{
int u = Q.front();
Q.pop();
vis[u] = 0;//消除标记
for(int i=0;i<G[u].size();++i)
{
Node e = G[u][i];
if(dis[e.to] < (dis[u]-e.b1)*e.a1)
{
dis[e.to] = (dis[u]-e.b1)*e.a1;
if(!vis[e.to])
{
vis[e.to] = 1;//添加标记
Q.push(e.to);
}
}
if(dis[x] > v) return true;//判断是否存在正环了
}
}
return false;
}
int main()
{
sddd(n,m,s);
scanf("%lf",&v);
while(m--)
{
int a,b;
double a1,b1,a2,b2;
sdd(a,b);
scanf("%lf %lf %lf %lf",&a1,&b1,&a2,&b2);
Node p,q;
p.to = b;p.a1 = a1;p.b1 = b1;
q.to = a;q.a1 = a2;q.b1 = b2;
G[a].pb(p);
G[b].pb(q);
}
if(spfa(s)) printf("YES\n");
else printf("NO\n");
}