【题解】LuoGu1073:Noip2009最优贸易

方法来自这位大佬
LuoGu题目传送门
【题解】
此题有一个非常巧妙的方法——分层图+SPFA
由题意可知,输出的答案只跟买入卖出价格有关,且买入卖出仅限一次
如果是普通宽搜的话我们很难维护这个买入卖出的状态,更新答案也比较麻烦

这个分层图方法就很方便
我们建立三层图

  1. 第一层:初始道路,可以走来走去没有权值
  2. 第二层:在同一层可以跟第一层一样走来走去,但是是从第一层通过来的,由第一层往第二层建立一条道路,表示买进,权值为 -价格
  3. 第三层:在同一层可以跟第一层一样走来走去,但是是从第二层通过来的,由第二层往第三层建立一条道路,表示卖出,权值为 价格

且终点在第三层的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.

猜你喜欢

转载自blog.csdn.net/ModestCoder_/article/details/81462118