题目大意:给一张迷宫地图,看看是否有等够在给的时间刚好到达终点,并且走过的不能重复走,记住,是刚好到达!!!
思路:搜索题,一开始只是轻微地作找到方案,作标记flag的剪枝,发现超时,原来还要奇偶剪枝,就是你一步一步走,如果你的位置到终点最小路程与剩余时间做差刚好是个奇数时,就要去掉。可能你会想,我们多走几格不就好了?但是你可以在稿纸上模拟一下,可以知道任何到达终点的路程(切记不能重复)刚好和最短路程的奇偶性一样。这点大牛们已经帮我们证明过了,当然你数学够6的话可以试试,反正身为菜鸟的我是不会啦,言归正传,剩下的就是搜索的基本思路啦,不知道那些排行榜的0ms的怎么写得(膜拜!),我的只能109ms,大佬又发现能再优化的一定告诉我哈!
代码如下:
#include<stdio.h>
#include<string.h>
#include<math.h>
int book[15][15],n,m,flag,rx,ry;
char map[15][15];
int next[4][2]={
{0,1},{1,0},{0,-1},{-1,0}
};
bool pan(int x,int y)
{
if(x<0||x>=n||y<0||y>=m||map[x][y]=='X')
return false;
return true;
}
void dfs(int time,int x,int y)
{
if(time<0)
return ;
if(time==0)
{
if(map[x][y]=='D')
{
flag=1;
return ;
}
return ;
}
int a,b,i;
a=abs(x-rx);
b=abs(y-ry);
if(time-a-b<0||(time-a-b)%2) //如果剩余的实践无法达到终点或者达到终点后还有时间就去掉(奇偶剪枝)
return ;
for(i=0;i<4;i++)
{
a=x+next[i][0];
b=y+next[i][1];
if(pan(a,b) && !book[a][b])
{
book[a][b]=1;
dfs(time-1,a,b);
book[a][b]=0;
}
if(flag) return ; //如果已经找到方案就不用再搜了(剪枝)
}
return ;
}
int main()
{
int i,j,time,x,y,p;
while(~scanf("%d%d%d",&n,&m,&time) && (n||m||time))
{
getchar();
memset(book,0,sizeof(book));
memset(map,0,sizeof(map));
for(i=p=0;i<n;i++)
scanf("%s",map[i]);
for(i=0;i<n;i++)
for(j=0;j<m;j++)
if(map[i][j]=='S')
{
x=i,y=j;
}
else if(map[i][j]=='D')
{
rx=i,ry=j;
}
else if(map[i][j]=='X')
{
p++;
}
if(n*m-p-time<=0) //剪枝,容易遗忘等于的情况
{
printf("NO\n");
continue;
}
book[x][y]=1;
flag=0;
dfs(time,x,y);
if(flag)
printf("YES\n");
else
printf("NO\n");
}
return 0;
}