最短路专题+spfa判断负环

题目链接:https://vjudge.net/problem/25713/origin
题目大意:有多种汇币,汇币之间可以交换,这需要手续费,当你用100A币交换B币时,A到B的汇率是29.75,手续费是0.39,那么你可以得到(100 - 0.39) * 29.75 = 2963.3975 B币。问s币的金额经过交换最终得到的s币金额数能否增加

货币的交换是可以重复多次的,如果有一个环使得某种货币一直增加,那么一定可以使得到的s币金额数增加,建图,一种货币就是一个点,货币交换作为有向边。spfa判断负环(一直可以松弛),松弛条件:(dis[d]-com[i])*rate[i]>dis[to[i]]
最短路专题+spfa判断负环_第1张图片

#include
#include
#include
#include
#define MAXN  105
using namespace std;
int info[MAXN],cnt[MAXN];
double dis[MAXN];
bool flag[MAXN];
int src=0;
int n;
double v;
vector<int> to,next;
vector<double>com,rate;
queue<int> q;
void init()
{
	memset(info,-1,sizeof(info));
	memset(cnt,0,sizeof(cnt));
	memset(flag,false,sizeof(flag));
	memset(dis,0,sizeof(dis));
	next.clear();
	to.clear();
	com.clear();
	rate.clear();
}
void add(int i,int j,double r,double c)
{
	to.push_back(j);
	next.push_back(info[i]);
	info[i]=to.size()-1;
	com.push_back(c);
	rate.push_back(r);
}
bool spfa(int s,double v)
{
	int src=s-1;
	dis[src]=v;
	q.push(src);
	cnt[src]++;
	flag[src]=true;
	cnt[src]++;
	while(!q.empty())
	{
		int d=q.front();
		q.pop();
		flag[d]=false;
		for(int i=info[d];i!=-1;i=next[i])
		{
			if((dis[d]-com[i])*rate[i]>dis[to[i]])
			{
				dis[to[i]]=(dis[d]-com[i])*rate[i];
				if(!flag[to[i]])
				{
					q.push(to[i]);
					flag[to[i]]=true;
					cnt[to[i]]++;
					if(cnt[to[i]]>n)
					return true;
				}	
			}
		}
	}

	return false;
}
int main()
{
	int m,s;
	int a,b;
	double c,d,e,f;
	scanf("%d%d%d%lf",&n,&m,&s,&v);
	init();
	for(int i=0;i<m;i++)
	{
		scanf("%d%d%lf%lf%lf%lf",&a,&b,&c,&d,&e,&f);
		add(a-1,b-1,c,d);
		add(b-1,a-1,e,f);
	}
	if(spfa(s,v))
	printf("YES");
	else
	printf("NO");
	return 0;
	
}

你可能感兴趣的:(最短路)