經過千辛萬苦小 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))最小。
輸入文件第一行是三個正整數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)。
輸出僅包含一個整數,表示在合法基礎上最小的總不和諧值。
input1
2 2 2
1
6 1
6 1
2 6
2 6
input2
2 2 2
0
5 1
5 1
2 5
2 5
output1
6
output2
12
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.