【图论】【poj 1860】Currency Exchange

问题

Description
一些货币兑换点正在我们的城市工作。我们假设每个兑换点尤其擅长兑换两种特定的货币,并且只进行对这些货币的兑换。可能有一些兑换点专门兑换相同的货币对。每个兑换点都有自己的汇率,货币A到货币B的汇率是你用1货币A换到的货币B的数量。每个兑换点也有一些佣金,即为你需要为你的兑换行动支付的金额。佣金总是从源货币扣除。
例如,如果你想要在汇率为29.75,并且佣金为0.39的兑换点将100美元兑换成俄罗斯卢布,你将会得到(100-0.39)*29.75=2963.3975卢布。
你有N种不同的货币可以在我们的城市进行兑换。我们为每一种货币制定从1到N的唯一一个整数。每个兑换点可以用6个数字形容:整数A和B——它交换的货币(表示为货币A和货币B);实数RAB,CAB,RBA和CBA——当它分别将货币A兑换成货币B和将货币B兑换成货币A时的汇率和佣金。
叫兽有一定数量的货币S,并且它希望它能以某种方式在一些兑换行动后增加它的资本。最后它的资金必须兑换为货币S。
帮助它解决这个棘手的问题。叫兽在进行它的兑换行动时资金总数必须始终非负。
Input
输入的第一行包含四个数字:N – 货币的数量,M – 兑换点的数量,S – 叫兽具有的货币种类,V – 叫兽具有的货币数量。
下面的M行每行包括6个数字 – 对相应的兑换点的描述。数字相隔一个或多个空格。1<=S<=N<=100,1<=M<=100,V是实数,0<=V<=10^3。
对于每个兑换点汇率和佣金都是实数,小数点后最多有两位小数。10^-2<=汇率<=10^2,0<=佣金<=10^2。
如果在一组兑换行动中没有兑换点被超过一次地使用,我们认为这组兑换行动是简单的。你可以认为最终数值和最初任何一个简单的兑换行动组的比例小于10^4。
Output
如果叫兽能增加它的财产,输出YES,否则输出NO。
Sample Input
3 2 1 20.0
1 2 1.00 1.00 1.00 1.00
2 3 1.10 1.00 1.10 1.00
Sample Output
YES
译者:Hzoi2008_叫兽

分析

我们可以把题目抽象成一个图,每种货币看成一个点,然后每个兑换点看成一条边,这样就可以构出一个图,显然图中有环。可以看成是一个最短路问题,用经典的spfa算法,逐次入队,只需要修改松弛的条件,思想是一样的。注意,要加上判断跳出的的语句,因为入队的条件是当前值比已产生的最优值还优。也就是说,如果存在可以获利的点的话,就会无限次入队。如果不存在则不会。由于图中所有的边都是双向的,很容易证明算法的正确性。

code

View Code
program liukee;
type lkj=record
next:longint;
a:double;
b:double;
end;

var
a:
array[1..100,0..100] of lkj;
visit:
array[1..100] of boolean;
tot:
array[1..100] of longint;
q:
array[1..1000000] of longint;
best:
array[1..100] of double;
n,m,st:longint;
sum:double;

procedure init;
var
i,x,y:longint;
a1,b1,a2,b2:double;
begin
readln(n,m,st,sum);
for i:=1 to m do
begin
readln(x,y,a1,b1,a2,b2);
inc(tot[x]);
a[x,tot[x]].next:
=y;
a[x,tot[x]].a:
=a1;
a[x,tot[x]].b:
=b1;
inc(tot[y]);
a[y,tot[y]].next:
=x;
a[y,tot[y]].a:
=a2;
a[y,tot[y]].b:
=b2;
end;
end;

procedure spfa;
var
l,r,i,now:longint;
begin
fillchar(visit,sizeof(visit),
0);
fillchar(q,sizeof(q),
0);
l:
=0;r:=1;
for i:=1 to n do best[i]:=-maxlongint;
best[st]:
=sum;
q[
1]:=st;
visit[st]:
=true;
while l<r do
begin
inc(l);
now:
=q[l];
visit[now]:
=false;
for i:=1 to tot[now] do
if best[a[now,i].next]<(best[now]-a[now,i].b)*a[now,i].a then
begin
best[a[now,i].next]:
=(best[now]-a[now,i].b)*a[now,i].a;
if best[st]>sum then
begin
writeln(
'YES');
exit;
end;
if not visit[a[now,i].next] then
begin
inc(r);
q[r]:
=a[now,i].next;
visit[q[r]]:
=true;
end;
end;
end;
writeln(
'NO');
end;

begin
init;
spfa;
end.

反思

要善于对题目分析,将其转化为图论模型,及对经典算法的深刻理解和修改。

posted @ 2011-02-27 19:25  liukee  阅读(305)  评论(0编辑  收藏  举报