SGOI9之《三维扫描》解题报告
   
  本题表述了一个三维空间的问题,其本质是求一个图中的连同分量。
  这个图以象素为顶点,如果任意两个相邻象素的差的绝对值不大于M,则在代表这两个像素的顶点间连一条边。建图以后可以发现,原题目中所描述的一个部件其实就是图中的一个连同分量,只需要遍历一遍图就可求出连同分量的个数。

算法流程如下:

  for x := 1 to L do
   for y := 1 to W do
    for z := 1 to H do
     if 象素(x, y, z) 还未被标记 then
     begin
      部件数加1
      扩展象素(x, y, z)所在的部件并标记该部件内的所有象素(广度搜索)
     end

程序清单如下:

{$A+,B-,D+,E+,F-,G-,I+,L+,N-,O-,P-,Q+,R+,S+,T-,V+,X+,Y+}
{$M 16384,0,655360}

const
 ifn = 'scan.in';
 ofn = 'scan.out';
 maxsize = 50;
 dx: array[1..6] of integer = (0, 0, 1, 0, 0, -1);
 dy: array[1..6] of integer = (0, 1, 0, 0, -1, 0);
 dz: array[1..6] of integer = (1, 0, 0, -1, 0, 0);

type
 Ptwo = ^Ttwo;
 Ttwo = array[1..maxsize, 1..maxsize] of integer;
 Pnode = ^Tnode;
 Tnode = record
  x, y, z: integer;
  next: Pnode;
 end;

var
 three: array[1..maxsize] of Ptwo;
 l, w, h, m: integer;
 total: longint;

procedure init;
var
 x, y, z: integer;
begin
 assign(input, ifn);
 reset(input);
 readln(l, w, h);
 readln(m);
 for x := 1 to l do
 begin
  new(three[x]);
  fillchar(three[x]^, sizeof(three[x]^), 0);
  for y := 1 to w do
   for z := 1 to h do
   begin
    read(three[x]^[y, z]);
    inc(three[x]^[y, z]);
   end;
 end;
 close(input);
end;

procedure fill(var node: Pnode; x, y, z: integer);
begin
 new(node);
 node^.x := x;
 node^.y := y;
 node^.z := z;
 node^.next := nil;
 three[x]^[y, z] := - three[x]^[y, z];
end;

procedure expand(x, y, z: integer);
var
 x2, y2, z2, i, key: integer;
 head, tail, temp: Pnode;
begin
 fill(head, x, y, z);
 tail := head;
 repeat
  key := - three[head^.x]^[head^.y, head^.z];
  for i := 1 to 6 do
  begin
   x2 := head^.x + dx[i];
   y2 := head^.y + dy[i];
   z2 := head^.z + dz[i];
   if (x2 > 0) and (x2 <= l) and (y2 > 0) and (y2 <= w) and
    (z2 > 0) and (z2 <= h) and (three[x2]^[y2, z2] > 0) and
    (abs(key - three[x2]^[y2, z2]) <= m) then
   begin
    fill(tail^.next, x2, y2, z2);
    tail := tail^.next;
   end;
  end;
  temp := head;
  head := head^.next;
  dispose(temp);
 until head = nil;
end;

procedure main;
var
 x, y, z: integer;
begin
 total := 0;
 for x := 1 to l do
  for y := 1 to w do
   for z := 1 to h do
    if three[x]^[y, z] > 0 then
    begin
     inc(total);
     expand(x, y, z);
    end;
end;

procedure show;
begin
 assign(output, ofn);
 rewrite(output);
 writeln(total);
 close(output);
end;

begin
 init;
 main;
 show;
end.

   

 
网站导航 | 关于曙光 | 联系我们 | 请提意见
Copyright © FuJian Sunshine Educational Info. Co.,Ltd.
福建曙光教育资讯有限公司 版权所有