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.

 

posted on 2013-12-03 21:15  BLADEVIL  阅读(248)  评论(0编辑  收藏  举报