3144:[HNOI2013]切糕 - BZOJ

题目描述 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。 
 
 
终于AC了
弱爆了,调一个网络流都调了一上午,各种异常错误应有尽有
这是一个很巧妙的网络流最小割,每一个竖列都要切一个点,所以最开始我们从上一直连到下面
但是还有第二个条件,相邻的两个点高度差不能超过D
先不管它
我们现在求出了一个最大流,但是不满足第二个条件
3144:[HNOI2013]切糕 <wbr>- <wbr>BZOJ
所以我们对于每一个点(x,y,z)都向(x-d,y,z)的相邻的4个点连一条无穷大的边,使这种情况不是最大流
3144:[HNOI2013]切糕 <wbr>- <wbr>BZOJ
然后就是套网络流的模板了
 
  1 var
  2     map:array[0..70000,-5..5]of longint;
  3     dis,his,pre:array[0..70000]of longint;
  4     vh:array[0..70000]of longint;
  5     fx:array[-5..5]of longint;
  6     a,b,c,d,flow:longint;
  7 
  8 procedure init;
  9 var
 10     i,j,k:longint;
 11 begin
 12     read(b,c,a,d);
 13     for i:=1 to a do
 14       for j:=1 to b do
 15         for k:=1 to c do
 16           begin
 17             read(map[(i-1)*b*c+(j-1)*c+k,1]);
 18             if i>d then
 19             begin
 20               if k>1 then map[(i-1)*b*c+(j-1)*c+k,2]:=100000000;
 21               if j>1 then map[(i-1)*b*c+(j-1)*c+k,3]:=100000000;
 22               if k<c then map[(i-1)*b*c+(j-1)*c+k,4]:=100000000;
 23               if j<b then map[(i-1)*b*c+(j-1)*c+k,5]:=100000000;
 24             end;
 25           end;
 26     fx[1]:=b*c;
 27     fx[2]:=-d*b*c-1;
 28     fx[3]:=-d*b*c-c;
 29     fx[4]:=-d*b*c+1;
 30     fx[5]:=-d*b*c+c;
 31     for i:=1 to 5 do
 32       fx[-i]:=-fx[i];
 33 end;
 34 
 35 function max(x,y:longint):longint;
 36 begin
 37     if x>y then exit(x);
 38     exit(y);
 39 end;
 40 
 41 procedure work;
 42 var
 43     i,j,aug,min:longint;
 44     flag:boolean;
 45 begin
 46     vh[0]:=a*b*c+2;
 47     i:=0;
 48     aug:=maxlongint;
 49     while dis[0]<=a*b*c+1 do
 50       begin
 51         flag:=false;
 52         his[i]:=aug;
 53         if i=0 then
 54           begin
 55             for j:=1 to b*c do
 56               if dis[0]=dis[j]+1 then
 57               begin
 58                 flag:=true;
 59                 pre[j]:=-1;
 60                 break;
 61               end;
 62             if flag then i:=j;
 63           end
 64         else
 65           for j:=-5 to 5 do
 66             if i+fx[j]>0 then
 67             if (map[i,j]>0)and(dis[i]=dis[i+fx[j]]+1) then
 68             begin
 69               flag:=true;
 70               pre[i+fx[j]]:=-j;
 71               if aug>map[i,j] then aug:=map[i,j];
 72               inc(i,fx[j]);
 73               if i>a*b*c then
 74               begin
 75                 inc(flow,aug);
 76                 while i<>0 do
 77                   begin
 78                     inc(map[i,pre[i]],aug);
 79                     dec(map[max(i+fx[pre[i]],0),-pre[i]],aug);
 80                     inc(i,fx[pre[i]]);
 81                     if i<0 then i:=0;
 82                   end;
 83                 aug:=maxlongint;
 84               end;
 85               break;
 86             end;
 87         if flag then continue;
 88         min:=a*b*c+1;
 89         if i=0 then
 90           begin
 91             for j:=1 to b*c do
 92               if min>dis[j] then min:=dis[j];
 93           end
 94         else
 95           for j:=-5 to 5 do
 96             if i+fx[j]>0 then
 97             if (map[i,j]>0)and(dis[i+fx[j]]<min) then min:=dis[i+fx[j]];
 98         dec(vh[dis[i]]);
 99         if vh[dis[i]]=0 then break;
100         dis[i]:=min+1;
101         inc(vh[dis[i]]);
102         if i<>0 then
103         begin
104           inc(i,fx[pre[i]]);
105           if i<0 then i:=0;
106           aug:=his[i];
107         end;
108       end;
109     write(flow);
110 end;
111 
112 begin
113     init;
114     work;
115 end.
View Code

 

posted @ 2014-03-05 14:27  Randolph87  阅读(402)  评论(0编辑  收藏  举报