bzoj 1221 软件开发 费用流

应该比较好看出来是费用流,那么就考虑怎么构图

首先我们把一天拆成两个点,XI,YI,分别代表这一天买了多少

和洗多少,再加入源和汇S,T

1.每一天我们可以买新的毛巾,所以连接一条从S到XI的边,流量为正无穷(因为可以买好多),费用为f

2.然后我们对于买来的毛巾可以洗,每天都产生need[i]的毛巾可以洗,那么连一条从S到YI的边,

流量为need[i],费用为0(因为只决定要洗,没有确定洗的方案,所以先不算费用)

3.每一条要用a方法洗的毛巾,我们连一条从YI到X(I+a+1)的边,流量为正无穷(下文解释),费用为fa的

4.每一条要用b方法洗的毛巾,我们连一条从YI到X(I+b+1)的边,流量为正无穷(下文解释),费用为fb的

5.因为每天剩下的毛巾,我们可以不当天洗,所以连接一条从YI到Y(I+1)的边,流量为正无穷,费用为0(所以每天可以洗

的毛巾的个数是可能会很多的,4,5建的边流量要是正无穷)

6.那么我们每天买的毛巾除了洗,还可以不洗,也就是直接扔掉,所以连一条XI到T的边,流量为need[i],费用为0

/**************************************************************
    Problem: 1221
    User: BLADEVIL
    Language: Pascal
    Result: Accepted
    Time:1952 ms
    Memory:8120 kb
****************************************************************/
 
//By BLADEVIL
var
    n, a, b, f, fa, fb  :longint;
    need                :array[0..1010] of longint;
    pre, other,len      :array[0..500010] of longint;
    cost                :array[0..500010] of longint;
    last                :array[0..4010] of longint;
    ss, tt              :longint;
    que                 :array[0..5000] of longint;
    dis                 :array[0..5000] of longint;
    flag                :array[0..5000] of boolean;
    father              :array[0..5000] of longint;
    ans                 :int64;
    l                   :longint;
      
function min(a,b:longint):longint;
begin
    if a>b then min:=b else min:=a;
end;
      
procedure connect(a,b,c,d:longint);
begin
    inc(l);
    pre[l]:=last[a];
    last[a]:=l;
    other[l]:=b;
    len[l]:=c;
    cost[l]:=d;
end;
      
procedure init;
var
    i                   :longint;
    use                 :longint;
begin
    read(n,a,b,f,fa,fb);
    for i:=1 to n do read(need[i]);
    l:=1;
    ss:=2*n+1;
    tt:=2*n+2;
    for i:=1 to n do
    begin
        connect(ss,2*i-1,maxlongint,f);
        connect(2*i-1,ss,0,-f);
        connect(2*i-1,tt,need[i],0);
        connect(tt,2*i-1,0,0);
        connect(ss,2*i,need[i],0);
        connect(2*i,ss,0,0);
        use:=i+a+1;
        if use<=n then
        begin
            use:=use*2-1;
            connect(2*i,use,maxlongint,fa);
            connect(use,2*i,0,-fa);
        end;
        use:=i+b+1;
        if use<=n then
        begin
            use:=use*2-1;
            connect(2*i,use,maxlongint,fb);
            connect(use,2*i,0,-fb);
        end;
    end;
    for i:=1 to n-1 do
    begin
        connect(2*i,2*i+2,maxlongint,0);
        connect(2*i+2,2*i,0,0);
    end;
end;
  
function spfa:boolean;
var
    q, p, cur               :longint;
    h, t                    :longint;
begin
    filldword(dis,sizeof(dis) div 4,maxlongint div 10);
    que[1]:=ss;
    dis[ss]:=0;
    h:=0; t:=1;
    while t<>h do
    begin
        h:=h mod 5000+1;
        cur:=que[h];
        flag[cur]:=false;
        q:=last[cur];
        while q<>0 do
        begin
            p:=other[q];
            if len[q]>0 then
            begin
                if dis[p]>dis[cur]+cost[q] then
                begin
                    father[p]:=q;
                    dis[p]:=dis[cur]+cost[q];
                    if not flag[p] then
                    begin
                        t:=t mod 5000+1;
                        que[t]:=p;
                        flag[p]:=true;
                    end;
                end;
            end;
            q:=pre[q];
        end;
    end;
    if dis[tt]=maxlongint div 10 then exit(false) else exit(true);
end;
  
procedure update;
var
    cur                     :longint;
    low                     :longint;
   
begin
    low:=maxlongint div 10;
    cur:=tt;
    while cur<>ss do
    begin
        low:=min(low,len[father[cur]]);
        cur:=other[father[cur] xor 1];
    end;
    cur:=tt;
    while cur<>ss do
    begin
        dec(len[father[cur]],low);
        inc(len[father[cur] xor 1],low);
        inc(ans,low*cost[father[cur]]);
        cur:=other[father[cur] xor 1]; 
    end;
end;
  
procedure main;
begin
    while spfa do update;
    writeln(ans);
end;
  
begin
    init;
    main;
end.

 

posted on 2013-12-12 09:23  BLADEVIL  阅读(538)  评论(0编辑  收藏  举报