TOXIC.PAS 5.9 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224
  1. {$R+}
  2. program Toxic_Game;
  3. const
  4. name1 = 'toxic.in'; {输入文件}
  5. name2 = 'toxic.out'; {输出文件}
  6. go : array[1..4, 1..2] of shortint {平面上4个方向的坐标增量}
  7. = ((0, 1), (1, 0), (0, -1), (-1, 0));
  8. six : array[1..6, 1..3] of shortint {立方体6个相邻面的坐标增量}
  9. = ((1, 0, 0), (0, 1, 0), (0, 0, 1),
  10. (-1, 0, 0), (0, -1, 0), (0, 0, -1));
  11. type
  12. Tsize = array[1..3] of integer;
  13. Tblocks = array[0..33, 0..33, 0..33] of shortint;
  14. var
  15. size : Tsize; {长方体的长、宽、高}
  16. StoE, EtoS, {StoE[i]由于坐标变换}
  17. BStoE : Tsize; {BStoE表示Best Size to Experiment,记录下最优的坐标变换}
  18. mx, my, mz : integer; {maxX、maxY、maxZ}
  19. ans, sum : integer; {ans存放当前最优解,sum存放当前吃掉的立方体数目}
  20. blocks : Tblocks; {存放当前路径的信息}
  21. {blocks[x,y,z]: -1表示走过该格 -2表示已经吃掉该格 大等于0表示当前暴露的面的数目}
  22. b2 : ^TBlocks; {记录路径,为“拾遗”做准备}
  23. outf : text; {输出文件}
  24. print : boolean; {寻找最优解答和打印解用同一个过程,print表示是否打印}
  25. procedure init; {文件初始化}
  26. var f : text;
  27. begin
  28. assign(f, name1);
  29. reset(f);
  30. readln(f, size[1], size[2], size[3]);
  31. close(f);
  32. assign(outf, name2);
  33. rewrite(outf)
  34. end;
  35. procedure initblocks; {初始化blocks}
  36. var x, y, z : integer;
  37. begin
  38. fillchar(blocks, sizeof(blocks), 255);
  39. for x := 1 to mx do
  40. for y := 1 to my do
  41. for z := 1 to mz do
  42. blocks[x, y, z] := 0
  43. end;
  44. procedure say(ch : char; x, y, z : integer); {当print=TRUE时输出一个命令}
  45. var o : Tsize;
  46. begin
  47. if not print then exit;
  48. o[ EtoS[1] ] := x;
  49. o[ EtoS[2] ] := y;
  50. o[ EtoS[3] ] := z;
  51. writeln(outf, ch, ' ', o[1], ' ', o[2], ' ', o[3])
  52. end;
  53. function eat_block(x, y, z : integer) : boolean; {吃掉立方体(x,y,z),返回是否成功}
  54. var i, xx, yy, zz : integer;
  55. begin
  56. if (x = 0) or (x > mx) or
  57. (y = 0) or (y > my) or
  58. (z = 0) or (z > mz) or
  59. (blocks[x, y, z] <> 1)
  60. then begin eat_block := false; exit end;
  61. eat_block := true;
  62. blocks[x, y, z] := -2;
  63. say('E', x, y, z);
  64. inc(sum);
  65. for i := 1 to 6 do
  66. begin
  67. xx := x + six[i, 1];
  68. yy := y + six[i, 2];
  69. zz := z + six[i, 3];
  70. if blocks[xx, yy, zz] >=0
  71. then inc(blocks[xx, yy, zz])
  72. end
  73. end;
  74. procedure pick_block(x, y, z : integer);
  75. {对(x,y,z)拾遗,如果立方体(x,y,z)只有一个面与路径接触,则吃掉(x,y,z)不会影响路径}
  76. var i, j, xx, yy, zz : integer;
  77. begin
  78. if (x = 0) or (x > mx) or
  79. (y = 0) or (y > my) or
  80. (z = 0) or (z > mz) or
  81. (blocks[x, y, z] <> 1)
  82. then exit;
  83. j := 0;
  84. for i := 1 to 6 do
  85. begin
  86. xx := x + six[i, 1];
  87. yy := y + six[i, 2];
  88. zz := z + six[i, 3];
  89. if (xx >= 1) and (xx <= mx) and
  90. (yy >= 1) and (yy <= my) and
  91. (zz >= 1) and (zz <= mz) and (b2^[xx, yy, zz] = -1)
  92. then inc(j)
  93. end;
  94. if j = 1 then eat_block(x, y, z)
  95. end;
  96. procedure pick_6(x, y, z : integer); {对6个方向拾遗}
  97. var i : integer;
  98. begin
  99. if (z > 0) and print
  100. then for i := 1 to 6 do
  101. pick_block(x + six[i, 1], y + six[i, 2], z + six[i, 3])
  102. end;
  103. procedure make_way; {按照构造的方法路径}
  104. var nx, ny, nz, ns : integer;
  105. {(nx, ny, nz)表示当前坐标,ns表示当前状态,ns=1表示在主线上移动,ns>1表示在相邻主线的衔接处}
  106. ford, upd : integer;
  107. procedure odd_plane; {奇数层的移动和吃食}
  108. var t, i, h : integer;
  109. begin
  110. eat_block(nx, ny, nz);
  111. pick_6(nx, ny, nz-1);
  112. blocks[nx, ny, nz-1] := -1;
  113. say('M', nx, ny, nz);
  114. if ns = 2
  115. then ns := 4
  116. else ns := 1;
  117. if ny = 1
  118. then upd := 1
  119. else upd := 3;
  120. repeat
  121. case ns of
  122. 1 : begin
  123. if nx = 1
  124. then ford := 2
  125. else ford := 4;
  126. h := 1;
  127. while eat_block(nx + go[ford, 1], ny, nz) do
  128. begin
  129. inc(h);
  130. eat_block(nx, ny, nz-1);
  131. if nz+1 = mz then eat_block(nx, ny, nz+1);
  132. if (upd <> 1) or (h < mx-1) then eat_block(nx, ny+1, nz);
  133. if (upd <> 3) or (h < mx-1) then eat_block(nx, ny-1, nz);
  134. pick_6(nx, ny, nz);
  135. blocks[nx, ny, nz] := -1;
  136. nx := nx + go[ford, 1];
  137. say('M', nx, ny, nz)
  138. end;
  139. ns := 2
  140. end;
  141. 2..4 : begin
  142. if eat_block(nx, ny + go[upd, 2], nz)
  143. then begin
  144. eat_block(nx, ny, nz-1);
  145. if nz+1 = mz then eat_block(nx, ny, nz+1);
  146. pick_6(nx, ny, nz);
  147. blocks[nx, ny, nz] := -1;
  148. ny := ny + go[upd, 2];
  149. say('M', nx, ny, nz);
  150. ns := ns mod 4+1
  151. end
  152. else break
  153. end
  154. end
  155. until false
  156. end;
  157. procedure even_plane; {偶数层的移动和吃食}
  158. begin
  159. if not eat_block(nx, ny, nz) then exit;
  160. pick_6(nx, ny, nz-1);
  161. blocks[nx, ny, nz-1] := -1;
  162. say('M', nx, ny, nz)
  163. end;
  164. begin
  165. {对坐标进行变换}
  166. sum := 0;
  167. EtoS[ StoE[1] ] := 1;
  168. EtoS[ StoE[2] ] := 2;
  169. EtoS[ StoE[3] ] := 3;
  170. mx := Size[ EtoS[1] ];
  171. my := Size[ EtoS[2] ];
  172. mz := Size[ EtoS[3] ];
  173. {开始构造}
  174. initblocks;
  175. blocks[1, 1, 1] := 1;
  176. nx := 1; ny := 1; nz := 0; ns := 3;
  177. for nz := 1 to mz do
  178. if odd(nz)
  179. then odd_plane
  180. else even_plane;
  181. {更新当前最优解}
  182. if sum > ans
  183. then begin ans := sum; b2^ := blocks; BStoE := StoE end
  184. end;
  185. {主程序}
  186. begin
  187. new(b2);
  188. init;
  189. ans := -1; min := maxint;
  190. print := false;
  191. for StoE[1] := 1 to 3 do
  192. for StoE[2] := 1 to 3 do
  193. for StoE[3] := 1 to 3 do
  194. if [ StoE[1], StoE[2], StoE[3] ] = [1..3]
  195. then make_way;
  196. StoE := BStoE;
  197. print := true;
  198. make_way;
  199. close(outf);
  200. writeln('Eat = ', sum);
  201. writeln('Rate = ', sum /mx/my/mz :0 :2)
  202. end.