codevs 切糕 網絡流

題目描述 Description

經過千辛萬苦小 A 得到了一塊切糕,切糕的形狀是長方體,小 A 打算攔腰將切糕切成兩半分給小 B。出於美觀考慮,小 A 希望切面能儘量光滑且和諧。於是她找到你,希望你能幫她找出最好的切割方案。 
出於簡便考慮,我們將切糕視作一個長 P、寬 Q、高 R 的長方體點陣。我們將位於第 z層中第 x 行、第 y 列上(1≤x≤P, 1≤y≤Q, 1≤z≤R)的點稱爲(x,y,z),它有一個非負的不和諧值 v(x,y,z)。一個合法的切面滿足以下兩個條件: 
1. 與每個縱軸(一共有 P*Q 個縱軸)有且僅有一個交點。即切面是一個函數 f(x,y),對於所有 1≤x≤P, 1≤y≤Q,我們需指定一個切割點 f(x,y),且 1≤f(x,y)≤R。 
2. 切面需要滿足一定的光滑性要求,即相鄰縱軸上的切割點不能相距太遠。對於所有的 1≤x,x’≤P 和 1≤y,y’ ≤Q,若|x-x’|+|y-y’|=1,則|f(x,y)-f(x’,y’)| ≤D,其中 D 是給定的一個非負整數。 
可能有許多切面f 滿足上面的條件,小A 希望找出總的切割點上的不和諧值最小的那個,即 ∑v(x,y, f(x,y))最小。

輸入描述 Input Description

輸入文件第一行是三個正整數P,Q,R,表示切糕的長P、寬Q、高R。第二行有一個非負整數D,表示光滑性要求。接下來是R個P行Q列的矩陣,第z個矩陣的第x行第y列是v(x,y,z) (1≤x≤P, 1≤y≤Q, 1≤z≤R)。

輸出描述 Output Description

輸出僅包含一個整數,表示在合法基礎上最小的總不和諧值。

樣例輸入 Sample Input

input1
2 2 2 

6 1 
6 1 
2 6 
2 6 
input2 
2 2 2 

5 1 
5 1 
2 5 
2 5

樣例輸出 Sample Output

output1

output2
12

數據範圍及提示 Data Size & Hint

100%的數據滿足P,Q,R≤40,0≤D≤R,且給出的所有的不和諧值不超過1000。 

var
    map:array[0..70000,-5..5]of longint;
    dis,his,pre:array[0..70000]of longint;
    vh:array[0..70000]of longint;
    fx:array[-5..5]of longint;
    a,b,c,d,flow:longint;
 
procedure init;
var
    i,j,k:longint;
begin
    read(b,c,a,d);
    for i:=1 to a do
      for j:=1 to b do
        for k:=1 to c do
          begin
            read(map[(i-1)*b*c+(j-1)*c+k,1]);
            if i>d then
            begin
              if k>1 then map[(i-1)*b*c+(j-1)*c+k,2]:=100000000;
              if j>1 then map[(i-1)*b*c+(j-1)*c+k,3]:=100000000;
              if k<c then map[(i-1)*b*c+(j-1)*c+k,4]:=100000000;
              if j<b then map[(i-1)*b*c+(j-1)*c+k,5]:=100000000;
            end;
          end;
    fx[1]:=b*c;
    fx[2]:=-d*b*c-1;
    fx[3]:=-d*b*c-c;
    fx[4]:=-d*b*c+1;
    fx[5]:=-d*b*c+c;
    for i:=1 to 5 do
      fx[-i]:=-fx[i];
end;
 
function max(x,y:longint):longint;
begin
    if x>y then exit(x);
    exit(y);
end;
 
procedure work;
var
    i,j,aug,min:longint;
    flag:boolean;
begin
    vh[0]:=a*b*c+2;
    i:=0;
    aug:=maxlongint;
    while dis[0]<=a*b*c+1 do
      begin
        flag:=false;
        his[i]:=aug;
        if i=0 then
          begin
            for j:=1 to b*c do
              if dis[0]=dis[j]+1 then
              begin
                flag:=true;
                pre[j]:=-1;
                break;
              end;
            if flag then i:=j;
          end
        else
          for j:=-5 to 5 do
            if i+fx[j]>0 then
            if (map[i,j]>0)and(dis[i]=dis[i+fx[j]]+1) then
            begin
              flag:=true;
              pre[i+fx[j]]:=-j;
              if aug>map[i,j] then aug:=map[i,j];
              inc(i,fx[j]);
              if i>a*b*c then
              begin
                inc(flow,aug);
                while i<>0 do
                  begin
                    inc(map[i,pre[i]],aug);
                    dec(map[max(i+fx[pre[i]],0),-pre[i]],aug);
                    inc(i,fx[pre[i]]);
                    if i<0 then i:=0;
                  end;
                aug:=maxlongint;
              end;
              break;
            end;
        if flag then continue;
        min:=a*b*c+1;
        if i=0 then
          begin
            for j:=1 to b*c do
              if min>dis[j] then min:=dis[j];
          end
        else
          for j:=-5 to 5 do
            if i+fx[j]>0 then
            if (map[i,j]>0)and(dis[i+fx[j]]<min) then min:=dis[i+fx[j]];
        dec(vh[dis[i]]);
        if vh[dis[i]]=0 then break;
        dis[i]:=min+1;
        inc(vh[dis[i]]);
        if i<>0 then
        begin
          inc(i,fx[pre[i]]);
          if i<0 then i:=0;
          aug:=his[i];
        end;
      end;
    write(flow);
end;
 
begin
    init;
    work;
end.

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章