NEERC2001,Northern Subregion POJ1860 Currency Exchange 题解

时间:2021-08-12
本文章向大家介绍NEERC2001,Northern Subregion POJ1860 Currency Exchange 题解,主要包括NEERC2001,Northern Subregion POJ1860 Currency Exchange 题解使用实例、应用技巧、基本知识点总结和需要注意事项,具有一定的参考价值,需要的朋友可以参考一下。


其实本来不想写题解的,但是由于这题把我坑到了,所以就来写个题解。

题目大意

\(N\) 中货币,\(M\) 个地方可以进行不同货币的转换,每个地方可以转换两种货币 \(A\)\(B\),其中两种货币的汇率分别是 \(R_{AB}\)\(R_{BA}\),交易是需要支付的手续费为 \(C_{AB}\)\(C_{BA}\),手续费从原来的货币里扣除。现在要问,如果一个人有货币 \(S\) \(V\) 单位,请问他是否能增加他的资本,当然必须换成货币 \(S\)
数据范围 \(1\le S\le N\ \le 100\ 1 \le M \le 100\ 0 \le V \le 10^3 \ -10^2 \le R,C \le 10^2\)

解题过程

第一反应:这不是判正环吗?随手写了个SPFA然后。。。

嘿嘿,WA了。难道是我不会写判负环?

上网去看了一下题解,发现他们都是直接判断能不能在货币 \(S\) 获得比 \(V\) 多的钱。
仔细一看: \(-10^2 \le R \le 10^2\),汇率还有负的?!
我也造了一组HACK数据:

3 2 100.0
1 2 1.00 1.00 0.00 0.00
2 3 1.10 1.10 1.10 1.10

显然如果找正环会输出 YES,但是答案显然是 NO,因为从货币 \(2\) 到货币 \(1\) 的汇率为 \(0\) ,在货币 \(2\)\(3\) 之间获得再多的钱最后也没用。
但是按照 SPFA 的算法,答案最后会在两个节点之间更新最长路,难道不会 TLE 吗?我们发现,在跑的时候钱的数量是指数级增长的,很快就爆 double 了,然后就会变成负的从而结束搜索,最后输出 NO。

最后注意多测数组清空。

代码:

#include<queue>
#include<cstdio>
#include<cstring>
#include<iostream>
#define maxn 139
using namespace std;
//#define debug
typedef int Type;
inline Type read(){
	Type sum=0;
	int flag=0;
	char c=getchar();
	while((c<'0'||c>'9')&&c!='-') c=getchar();
	if(c=='-') c=getchar(),flag=1;
	while('0'<=c&&c<='9'){
		sum=(sum<<1)+(sum<<3)+(c^48);
		c=getchar();
	}
	if(flag) return -sum;
	return sum;
}
int head[maxn],nex[maxn<<1],to[maxn<<1],k;
double r[maxn<<1],c[maxn<<1];
#define add(x,y,rx,cx) nex[++k]=head[x];\
head[x]=k; to[k]=y; r[k]=rx; c[k]=cx;
int n,m,x,y;
double rx1,cx1,rx2,cx2;
struct JTZ{
	int s;
	double v;
}cur;
queue<JTZ> q,E;
int cnt[maxn],vis[maxn],st; 
double dist[maxn],v0;
void work(){
    cur.s=read(); cin>>cur.v;
    st=cur.s; v0=cur.v;
    for(int i=1;i<=m;i++){
    	cin>>x>>y;
    	cin>>cx1>>rx1>>cx2>>rx2;
    	add(x,y,rx1,cx1);
    	add(y,x,rx2,cx2);
	}
	dist[cur.s]=cur.v;
	q.push(cur);
	while(!q.empty()){
		cur=q.front(); q.pop(); vis[cur.s]=0; cur.v=dist[cur.s];
		//printf("%0.2lf\n",cur.v);
		for(int i=head[cur.s];i;i=nex[i])
		    if(dist[to[i]]<(cur.v-r[i])*c[i]&&c[i]>0){
		    	dist[to[i]]=(cur.v-r[i])*c[i];
				if(!vis[to[i]]){
					cnt[to[i]]++; vis[to[i]]=1;
					//if(cnt[to[i]]>n){ printf("YES\n"); return; } 
					q.push((JTZ){to[i],dist[to[i]]});
				}
			}
		if(dist[st]>v0){
			printf("YES\n");
			return;
		}
	}
	printf("NO\n");
	return;
}
int main(){
	//freopen("1.in","r",stdin);
	//freopen("my.out","w",stdout);
    while(scanf("%d%d",&n,&m)!=EOF){
    	k=0; memset(dist,0,sizeof(dist));
    	q=E; memset(cnt,0,sizeof(cnt));
    	memset(vis,0,sizeof(vis));
    	memset(head,0,sizeof(head));
		work();
	}
	return 0;
}

原文地址:https://www.cnblogs.com/jiangtaizhe001/p/15131886.html