bzoj 1070 修车 费用流

 对于这道题,我们看数据范围应该是费用流(起码我的第一反应是。。。)

然后仔细想想发现可做,那么就开始构图

对于第I个修理工,我们可以让他修好多辆车,那么假设一个人修了J辆车,

在他修他修的第K辆车的时候,会让后面的j-k辆车的每个人多等他修k车的时间

那么我们设每个人一共修了n辆车,他倒数第j个修的车的代价就是j*time(修这辆车的代价)

那么我们就对于每个人拆点,拆成N个点,代表他倒数第J个修的哪个车,然后求最小费用最大流就行了

 

数据范围开始看成60,60了,数组开的不合适,后来懒得改了。。。。

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

    Problem: 1070

    User: BLADEVIL

    Language: Pascal

    Result: Accepted

    Time:556 ms

    Memory:8532 kb

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

 

//By BLADEVIL

var

    n, m                    :longint;

    time                    :array[0..100,0..100] of longint;

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

    l                       :longint;

    last                    :array[-10..5000] of longint;

    tot                     :longint;

    st, fin                 :longint;   

    que                     :array[0..100000] of longint;

    dis, father             :array[-10..5000] of longint;

    ans                     :longint;

    flag                    :array[-10..5000] of boolean;

     

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, j, k                 :longint;

 

begin

    read(n,m); l:=1;

    for i:=1 to m do

        for j:=1 to n do read(time[j,i]);

     

    st:=-1; fin:=-2;

    tot:=m;

    for i:=1 to m do

    begin

        connect(i,fin,1,0);

        connect(fin,i,0,0);

    end;

    for i:=1 to n do

        for j:=1 to m do

        begin

            inc(tot);

            for k:=1 to m do

            begin

                connect(tot,k,1,j*time[i,k]);

                connect(k,tot,0,-j*time[i,k]);

            end;

        end;

    for i:=m+1 to tot do

    begin

        connect(st,i,1,0);

        connect(i,st,0,0);

    end;

end;

 

procedure spfa;

var

    q, p, cur               :longint;

    h, t                    :longint;

begin

    filldword(dis,sizeof(dis) div 4,maxlongint div 10);

    que[1]:=st;

    dis[st]:=0;

    h:=0; t:=1;

    while t<>h do

    begin

        h:=h mod 100000+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 100000+1;

                        que[t]:=p;

                        flag[p]:=true;

                    end;

                end;

            end;

            q:=pre[q];

        end;

    end;

end;

 

procedure update;

var

    cur                     :longint;

    low                     :longint;

 

begin

    low:=maxlongint div 10;

    cur:=fin;

    while cur<>st do

    begin

        low:=min(low,len[father[cur]]);

        inc(ans,cost[father[cur]]);

        cur:=other[father[cur] xor 1];

    end;

    cur:=fin;

    while cur<>st do

    begin

        dec(len[father[cur]],low);

        inc(len[father[cur] xor 1],low);

        cur:=other[father[cur] xor 1]; 

    end;

end;

 

procedure main;

begin

    ans:=0;

    while true do

    begin

        spfa;

        if dis[fin]=maxlongint div 10 then break;

        update;

    end;

    writeln(ans/m:0:2);

end;

 

begin

    init;

    main;

end.

 

你可能感兴趣的:(ZOJ)