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;
}