POJ_1860_Currency Exchange_最短路算法判环

这两天跑步晚上睡得不够早,导致体能有点不足,今天好虚的感觉,有点想休息一天,但是一想到我这么水,还是来写题解吧。今天写的是今天和昨天两天做的不是特别水的水题。


题意:

有N种现金,有M个换钱的地方,一个地方可以进行两种货币之间的双向兑换。把a币兑换成b币,需要付手续费c,兑换率为r,则用x单位的a币可以得到(a-c)*r的b币。求是否存在一种方法,通过兑换的方式,增加钱的数量。



Input

The first line of the input contains four numbers: N - the number of currencies, M - the number of exchange points, S - the number of currency Nick has and V - the quantity of currency units he has. The following M lines contain 6 numbers each - the description of the corresponding exchange point - in specified above order. Numbers are separated by one or more spaces. 1<=S<=N<=100, 1<=M<=100, V is real number, 0<=V<=10 3.
For each point exchange rates and commissions are real, given with at most two digits after the decimal point, 10 -2<=rate<=10 2, 0<=commission<=10 2.
Let us call some sequence of the exchange operations simple if no exchange point is used more than once in this sequence. You may assume that ratio of the numeric values of the sums at the end and at the beginning of any simple sequence of the exchange operations will be less than 10 4.

Output

If Nick can increase his wealth, output YES, in other case output NO to the output file.


这题乍一看是广搜的节奏,但是还是用bellman的过程写了,最后还是WA了,后来想明白了为什么,也知道了为什么不能用广搜而要用最短路算法。

这个题不是为了求最短路而用最短路算法,而是为了判断环。由于这个图是双向的,所以能到一个点肯定可以回去,如果在某一块存在正环,那么价值就可以无限增大,总有一天再回到起点可以大于原来起点的值。

所以只要用bellman或者SPFA判出正环,就返回true,如果不存在环,则肯定不可能增大,返回false。最短路或者说最长路的数值没有意义。


代码如下:

#include<iostream>
#include<cstdio>
#include<cstring>
#include<string>
#include<cmath>
using namespace std;
#define mxn 110
#define mxm 250
int first[mxn],nxt[mxm],vv[mxm],cnt;
double rr[mxm],cc[mxm];
bool dcmp(double x,double y){
	return fabs(x-y)<0.00000001;
}
void add(int u,int v,double r,double c){
	nxt[cnt]=first[u];
	first[u]=cnt;
	vv[cnt]=v;
	rr[cnt]=r;
	cc[cnt++]=c;
}
void init(){
	memset(first,-1,sizeof(first));
	cnt=0;
}
int n,m,s;
double st,money[mxn];
int rec[mxn];
double ex(int now,int k){
	if(money[now]<cc[k]&&!dcmp(money[now],cc[k]))
		return money[vv[k]];
	return max((money[now]-cc[k])*rr[k],money[vv[k]]);
}
bool bellman(){
	memset(rec,0,sizeof(rec));
	memset(money,0,sizeof(money));
	money[s]=st;
	for(int i=0;i<2*n;++i){
		bool flag=false;
		for(int j=1;j<=n;++j)
			for(int k=first[j];k!=-1;k=nxt[k]){
				double tem=ex(j,k);
				if(tem>money[vv[k]]){
					++rec[vv[k]];
					money[vv[k]]=tem;
					flag=true;
				}
			}
		if(!flag)	break;
	}
	for(int i=1;i<=n;++i)
		if(rec[i]>=n)	return true;
	if(money[s]>st&&!dcmp(money[s],st))
		return true;
	return false;
}
int main(){
	while(scanf("%d%d%d%lf",&n,&m,&s,&st)!=EOF){
		init();
		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);
		}
		bool ans=bellman();
		if(ans)	puts("YES");
		else	puts("NO");
	}
	return 0;
}


评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值