第四题(50分)(每个测试数据2分)
提交文件:game.exe
输入文件:game.in
输出文件:game.out
题目描述:
下面介绍一个小游戏:
在一个M×N的板上,有部分格子被标记为障碍(例如上图黑色标示的格子)。你任选一个空白格子放置一个小球(如上图灰点所示),并选择小球滚动的方向(上,下,左,右),小球将在板上一直滚动直至它碰到障碍,或板的边界,或它之前经过的格子。如果小球遇到以上情况之一将停下,你可以给它另选滚动的方向,然后小球将以同样的方式前进。如果小球在四个方向上都无法继续滚动,游戏结束,这时假如小球的轨迹覆盖板上所有的空白格子,你将获胜。上图展示的轨迹就是一个仅用10步获胜的例子。
你的任务是对给定板子,计算赢得游戏所需的最少步数。
输入格式(map.in):
输入的第一行是用空格分隔的两个正整数m和n(m,n<=30),分别板子的高和宽。接下来的m行,每行有n个字符,含义如下:
‘.’:该格是空白格子;
‘*’:该格被标记为障碍。
我们保证板子不会全部被标记为障碍。
输出格式(map.out):
输出仅一个整数,表示计算赢得游戏所需的最少步数。假如无法取胜,则输出-1。
样例
game.in | game.out |
5 5 **... ..... ....* ..*.. ..... | 10 |
题解:从每个可走的点搜索。剪枝:如果当前走的步数大于之前找到的答案最小值可以直接结束这个点
const
maxn=40;
fx:array[1..4,1..2]of longint=((-1,0),(1,0),(0,-1),(0,1));
inf='game.in';
ouf='game.out';
var
a:array[0..maxn+1,0..maxn+1]of boolean;
n,m,i,j,ans,sum:longint;
procedure init;
var
i,j:longint;
ch:char;
begin
readln(m,n);
fillchar(a,sizeof(a),true);
for i:=1 to m do
begin
for j:=1 to n do
begin
read(ch);
if ch='*' then
begin
inc(sum);
a[i,j]:=false;
end;
end;
readln;
end;
fillchar(a[0],sizeof(a[0]),false);
fillchar(a[m+1],sizeof(a[m+1]),false);
for i:=1 to m do
begin
a[i,0]:=false;
a[i,n+1]:=false;
end;
ans:=maxlongint;
end;
procedure dfs(dep,x,y,tot:longint);
var
i,px,py:longint;
begin
if dep>=ans then exit;
if tot=n*m-sum then
begin
if dep<ans then ans:=dep;
exit;
end;
for i:=1 to 4 do
begin
px:=x;py:=y;
while a[px+fx[i,1],py+fx[i,2]] do
begin
px:=px+fx[i,1];py:=py+fx[i,2];
a[px,py]:=false;
end;
if (px<>x)or(py<>y)then
begin
dfs(dep+1,px,py,tot+abs(px-x)+abs(py-y));
while (x<>px)or(y<>py) do
begin
a[px,py]:=true;
px:=px-fx[i,1];py:=py-fx[i,2];
end;
end;
end;
end;
begin
assign(input,inf);reset(input);
assign(output,ouf);rewrite(output);
init;
for i:=1 to m do
for j:=1 to n do
if a[i,j] then
begin
a[i,j]:=false;
dfs(0,i,j,1);
a[i,j]:=true;
end;
if ans=maxlongint then ans:=-1;
writeln(ans);
close(input);close(output);
end.