https://vjudge.net/contest/375481#problem/E
一开始很快写完了判正权回路的代码 ,但是一直超时 ,发现错误是st【j】数组的添加一定要在数组特判条件内,没注意到。
总体思路:由题意可知,最终货币要要变成s,即变成原来货币。还要非负,所以就是要求出是否存在一个正权回路。
1.先给a,b 双向加边(加边代表的是货币的兑换流程线)
2.在SPFA函数里 用队列来存需要更新的点
3.遍历每个需要更新的点的出边 做数值特判 符合比之前的钱多的条件 则存在正权边 然后把这个点的cnt【j】用上一个点cnt[t]的数值更新;
4.如果cnt[j]大于n-1条边 抽屉原理 即必定存在正权回路 ,否则不存在。
#include<iostream>
#include<cstdio>
#include<queue>
#include<cstring>
using namespace std;
const int N=110;
int e[N*2],ne[N*2],h[N*2],cnt[2*N]; //双向边开两倍
double dist[N],w1[2*N],w2[2*N];
int n,m,s,idx;
double v;
bool st[N];
void add(int a,int b,double c,double d)
{
e[idx]=b,w1[idx]=c,w2[idx]=d,ne[idx]=h[a],h[a]=idx++;
}
bool SPFA()
{
queue<int>q;
dist[s]=v;
st[s]=true;
q.push(s);
while(q.size())
{
int t=q.front();
q.pop();
st[t]=false;
for(int i=h[t];i!=-1;i=ne[i])
{
int j=e[i];
if(dist[j]<(dist[t]-w2[i])*w1[i])
{
dist[j]=(dist[t]-w2[i])*w1[i];
cnt[j]=cnt[t]+1; //把上一个边的正权边数+1
if(cnt[j]>=n) return true; //正权边数大于n-1条即一定存在正权回路
if(!st[j]) // 给st赋值一定要在 特判条件内 因为这样的j才是符合条件的
{
q.push(j);
st[j]=true;
}
}
}
}
return false;
}
int main()
{
cin>>n>>m>>s>>v;
memset(h,-1,sizeof h);
for(int i=0;i<m;i++)
{
int a,b;
scanf("%d%d",&a,&b);
double rate,cost;
cin>>rate>>cost;
add(a,b,rate,cost);
cin>>rate>>cost;
add(b,a,rate,cost);
}
if(SPFA()) cout<<"YES";
else cout<<"NO";
}