方法来自这位大佬
LuoGu题目传送门
【题解】
此题有一个非常巧妙的方法——分层图+SPFA
由题意可知,输出的答案只跟买入卖出价格有关,且买入卖出仅限一次
如果是普通宽搜的话我们很难维护这个买入卖出的状态,更新答案也比较麻烦
这个分层图方法就很方便
我们建立三层图
- 第一层:初始道路,可以走来走去没有权值
- 第二层:在同一层可以跟第一层一样走来走去,但是是从第一层通过来的,由第一层往第二层建立一条道路,表示买进,权值为 -价格
- 第三层:在同一层可以跟第一层一样走来走去,但是是从第二层通过来的,由第二层往第三层建立一条道路,表示卖出,权值为 价格
且终点在第三层的n,最终结果与0比较即可
这个方法码量很小,十分优美
Code:
uses math;
var
q,dis,dist,next,u,head,w:array[0..1000000] of longint;
vis:array[0..1000000] of boolean;
n,m,x,y,z,i,h,tail,e,ans,num:longint;
procedure add(x,y,z:longint);
begin
inc(num);
u[num]:=y;
dist[num]:=z;
next[num]:=head[x];
head[x]:=num;
end;
begin
readln(n,m);
for i:=1 to n do read(w[i]);
for i:=1 to m do
begin
readln(x,y,z);
add(x,y,0);
add(x+n,y+n,0);
add(x+n+n,y+n+n,0);
add(x,y+n,-w[y]);
add(x+n,y+n+n,w[y]);
if z=2 then
begin
add(y,x,0);
add(y+n,x+n,0);
add(y+n+n,x+n+n,0);
add(y,x+n,-w[x]);
add(y+n,x+n+n,w[x]);
end;
end;
q[1]:=1;
tail:=1;
for i:=2 to 3*n do dis[i]:=-maxlongint;
while h<tail do
begin
inc(h);
x:=q[h];
vis[x]:=false;
i:=head[x];
while i>0 do
begin
e:=u[i];
if (dis[e]<dis[x]+dist[i]) then
begin
dis[e]:=dis[x]+dist[i];
if not vis[e] then
begin
inc(tail);
q[tail]:=e;
vis[e]:=true;
end;
if e=3*n then ans:=max(ans,dis[e]);
end;
i:=next[i];
end;
end;
writeln(ans);
end.