POJ3009 Curling 2.0 \text{POJ3009 Curling 2.0} POJ3009 Curling 2.0
题意简述
有一个冰壶,从起始点开始,经过移动到终点。
移动规则:
-
可以向一个方向一直运动直到碰到石头。
-
如果前方就是石头,不能往这个方向移动。
-
不能出界。
-
在任何时间移动到终点胜利。
求出最短步数。
题解
算法:IDDFS迭代加深
用maxstep
控制深度,用Is_Solved
表示是否在10步之内有解(输入前更新)。
异于一般DFS的地方:
for(maxstep=1;maxstep<=10&&!DFS(sx,sy,0);maxstep++);
此处的DFS是bool
型的,DFS(sx,sy,0)
表示从
(
s
x
,
s
y
)
(sx,sy)
(sx,sy)开始,在走不超过
m
a
x
s
t
e
p
maxstep
maxstep步是否有解。
如此渐渐迭代,不会出现爆栈RE或无止境的情况。
最后输出maxstep
即可。
DFS
部分:
First of all:判断此时步数是否超过了maxstep
,超过先退出。
Then:向4个方向搜。
同一般迷宫类题一样,此处用方向数组。
每一个方向的搜索流程:
- 向一个方向一直走,碰到障碍or边界停下。
- 判断是因障碍还是边界停下的,若为后者,
continue
。 - 如果和原来相比一步都没走(上述题意的第2点),
continue
。 - 打碎目前障碍,若:
DFS(x,y,step+1)==1
,直接return 1
;反之还原障碍,continue
。
代码实现:
#include<cstdio>
#include<cstring>
using namespace std;
const int dx[5]={0,0,0,1,-1},dy[5]={0,1,-1,0,0};
int A[201][201];
int R[101];
int W,H;
int sx,sy;
int maxstep=0;
bool Is_Solved=0;
bool DFS(int x,int y,int step)
{
if(step>=maxstep)return 0;
int now_x=x,now_y=y;
for(register int i=1;i<=4;i++)
{
x=now_x,y=now_y;
while(x+dx[i]>=1&&y+dy[i]>=1&&x+dx[i]<=W&&y+dy[i]<=H&&A[x+dx[i]][y+dy[i]]!=1)
{
x+=dx[i],y+=dy[i];
if(A[x][y]==3){Is_Solved=1;return 1;}
}
if(A[x+dx[i]][y+dy[i]]==1&&(now_x!=x||now_y!=y))
{
A[x+dx[i]][y+dy[i]]=0;
if(DFS(x,y,step+1))return 1;//#3
A[x+dx[i]][y+dy[i]]=1;
}
}
return 0;//#4
}
signed main()
{
register int cnt=0;
register int i,j;
while(scanf("%d %d",&H,&W),W||H)//#1
{
memset(A,0,sizeof(A));//#2
Is_Solved=0;
for(i=1;i<=W;i++)
for(j=1;j<=H;j++)
{
scanf("%d",&A[i][j]);
if(A[i][j]==2)
sx=i,sy=j;
}
for(maxstep=1;maxstep<=10&&!DFS(sx,sy,0);maxstep++);
if(Is_Solved)
R[++cnt]=maxstep;
else
R[++cnt]=-1;
}
for(i=1;i<=cnt;i++)printf("%d\n",R[i]);
return 0;
}
注释:
#1:个人习惯先输入行数,再输入列数。所以在输入时掉换了一下。
#2:为什么要memset
呢?因为这里我的出界判断是以面前是否为障碍来判断的。若前一个数据比后一个规模小,边界外可能也是1,就造成了出界而没有排除掉的情况而WA。
#3:以经return 1
了,就无需回溯了。
#4:一定要返回0!!!否则会返回一个随机的东西,导致答案错误。