bzoj 1497 最小割模型

我们可以对于消费和盈利的点建立二分图,开始答案为所有的盈利和,

那么源向消费的点连边,流量为消费值,盈利向汇连边,流量为盈利值

中间盈利对应的消费连边,流量为INF,那么我们求这张图的最小割,用

开始的答案减去最小割就是答案,因为最小割的存在不是左面就是右面,

割左面,代表建这条路,需要对应的消费,那么割右面代表不要这项盈利,

那本来加进去的盈利应该减掉,所以可以这样更新答案。

/**************************************************************

    Problem: 1497

    User: BLADEVIL

    Language: Pascal

    Result: Accepted

    Time:496 ms

    Memory:13116 kb

****************************************************************/

 

//By BLADEVIL

var

    n, m                        :longint;

    pre, other, len             :array[0..1000010] of longint; 

    last                        :array[0..100010] of longint;

    l                           :longint;

    source, sink                :longint;

    ans                         :longint;

    que, d                      :array[0..100010] of longint;

     

function min(a,b:longint):longint;

begin

    if a>b then min:=b else min:=a;

end;

 

procedure connect(x,y,z:longint);

begin

    inc(l);

    pre[l]:=last[x];

    last[x]:=l;

    other[l]:=y;

    len[l]:=z;

end;

     

procedure init;

var

    i                           :longint;

    x, y, z                     :longint;

begin

    read(n,m); source:=n+m+2; sink:=source+1;

    l:=1;

    for i:=1 to n do

    begin

        read(x);

        connect(source,i,x);

        connect(i,source,0);

    end;

    for i:=n+1 to n+m do

    begin

        read(x,y,z);

        connect(x,i,maxlongint div 10);

        connect(i,x,0);

        connect(y,i,maxlongint div 10);

        connect(i,y,0);

        connect(i,sink,z);

        connect(sink,i,0);

        ans:=ans+z;

    end;

end;

 

function bfs:boolean;

var

    q, p, cur                   :longint;

    h, t                        :longint;

begin

    fillchar(d,sizeof(d),0);

    h:=0; t:=1; d[source]:=1;

    que[1]:=source;

    while h<t do

    begin

        inc(h);

        cur:=que[h];

        q:=last[cur];

        while q<>0 do

        begin

            p:=other[q];

            if (len[q]>0) and (d[p]=0) then

            begin

                inc(t);

                que[t]:=p;

                d[p]:=d[cur]+1;

                if p=sink then exit(true);

            end;

            q:=pre[q];

        end;

    end;

    exit(false);

end;

 

function dinic(x,flow:longint):longint;

var

    tmp, rest                   :longint;

    q, p                        :longint;

begin

    if x=sink then exit(flow);

    rest:=flow;

    q:=last[x];

    while q<>0 do

    begin

        p:=other[q];

        if (len[q]>0) and (d[p]=d[x]+1) and (rest>0) then

        begin

            tmp:=dinic(p,min(len[q],rest));

            dec(rest,tmp);

            dec(len[q],tmp);

            inc(len[q xor 1],tmp);

        end;

        q:=pre[q];

    end;

    exit(flow-rest);

end;

 

procedure main;

begin

    while bfs do ans:=ans-dinic(source,maxlongint div 10);

    writeln(ans);

end;

 

begin

    init;

    main;

end.

 

你可能感兴趣的:(ZOJ)