题目注意点:要t时刻恰好到达!
各种剪枝。
①时间超了,直接return
②求出结果了,以后的全部直接return
③题目一开始,如果可走区间小于要求时间,直接return
④奇偶剪枝:对于每次的dfs,剩余时间减去当前点到达目的地的直接距离 所得到的那个值如果是偶数,继续运行。如果是奇数return。 因为那个数是留给我们乱走绕远路的,如果是奇数的话,我们走不回来了。
#include <stdio.h>
#include <string.h>#include <math.h>
int n,m,t;
char mp[10][10];
int flag;
int di,dj,wall;
int to[4][2] = {{0,-1},{0,1},{-1,0},{1,0}};
void dfs(int si,int sj,int cnt)
{
if(cnt>t) //剪枝:时间超了,直接return
return ;
int i,tem;
if(si>n || sj>m || si<=0 || sj <= 0)
return ;
if(cnt == t && si == di && sj == dj)
flag = 1;
if(flag) //剪枝:已经求出结果了,我们虽然不能直接返回主函数,但是我们要不停的return,放置做无用功
return ;
//
//剪枝:奇偶剪枝。我们先求出当前点到目的地的最近路程。如果我们想要过去,那么最好
//的方法是走最近路程,但是我们一般是要绕一下,剩余时间减去最近路程,获得的数是提
//供给我们绕圈子的路,这个数必须是个偶数,这样才能保证我们能绕回来。判断是否为偶数
//和负数
int s1 = si-di;
int s2 = sj-dj;
if(s1<0)
s1=-s1;
if(s2<0)
s2=-s2;
tem = t-cnt - s1 - s2;
if(tem<0 || tem&1)
return;
/
for(i = 0; i<4; i++)
{
if(mp[si+to[i][0]][sj+to[i][1]]!='X')
{
mp[si+to[i][0]][sj+to[i][1]]='X';//走过的地方变为墙
dfs(si+to[i][0],sj+to[i][1],cnt+1);
mp[si+to[i][0]][sj+to[i][1]]='.';//迷宫还原,以便下次广搜
}
}
return ;
}
int main()
{
int i,j,si,sj;
while(~scanf("%d%d%d%*c",&n,&m,&t))
{
if(!n && !m && !t)
break;
wall = 0;
for(i = 1; i<=n; i++)
{
for(j = 1; j<=m; j++)
{
scanf("%c",&mp[i][j]);
if(mp[i][j] == 'S')
{
si = i;
sj = j;
}
else if(mp[i][j] == 'D')
{
di = i;
dj = j;
}
else if(mp[i][j] == 'X')
wall++;
}
getchar();
}
if(n*m-wall-1<t) //剪枝:如果可以走的位置小于要求步数了,直接GG
{
printf("NO\n");
continue;
}
flag = 0;
mp[si][sj] = 'X';
dfs(si,sj,0);
if(flag)
printf("YES\n");
else
printf("NO\n");
}
return 0;
}