简单的dfs和剪枝,卡了一天才过。
注意:是t时刻恰好到达door,不能提前也不能滞后。
还有一个小技巧叫做奇偶剪枝,如下:
从一个点a到另一个点b走的步数最少应该是abs(ax-bx)+abs(ay-by);即上下和左右都向目标的方向走,每一步都更近,示意如下:
s | ||||
| | ||||
| | ||||
| | ||||
+ | — | — | — | e |
这样可以直接判断出要求的时间t(即步数)是否符合这个规律,如果不符合直接NO,退出。
更直观的解释:
可以把map看成这样:
01 0 1 0 1
10 1 0 1 0
01 0 1 0 1
10 1 0 1 0
01 0 1 0 1
从为0 的格子走一步,必然走向为1 的格子
从为1 的格子走一步,必然走向为0 的格子
即:
0 ->1或1->0必然是奇数步
0->0 走1->1必然是偶数步
所以当遇到从 0 走向 0 但是要求时间是奇数的,或者, 从 1 走向 0 但是要求时间是偶数的 都可以直接判断不可达!
代码:
#include<stdio.h>
#include<iostream>
#include<string.h>
#include<algorithm>
#include<stdlib.h>
#include<cstdlib>
#include<math.h>
#define L long long
#define max(a,b) a>b?a:b;
#define min(a,b) a>b?b:a;
using namespace std;
char map[9][9];
int v[9][9]={0};
int n,m,t;
int ans=0,flag=0;
int dx,dy;
void dfs(int s,int sx,int sy)
{
if(ans)return ;
if(s==t&&sx==dx&&sy==dy)
{
ans=1;return ;
}
if(s>t)
return ;
if(!v[sx+1][sy]&&map[sx+1][sy]!='X')
{
v[sx+1][sy]=1;
dfs(s+1,sx+1,sy);
v[sx+1][sy]=0;
}
if(!v[sx][sy+1]&&map[sx][sy+1]!='X')
{
v[sx][sy+1]=1;
dfs(s+1,sx,sy+1);
v[sx][sy+1]=0;
}
if(!v[sx-1][sy]&&map[sx-1][sy]!='X')
{
v[sx-1][sy]=1;
dfs(s+1,sx-1,sy);
v[sx-1][sy]=0;
}
if(!v[sx][sy-1]&&map[sx][sy-1]!='X')
{
v[sx][sy-1]=1;
dfs(s+1,sx,sy-1);
v[sx][sy-1]=0;
}
}
void p()
{
for(int i=0;i<=n+1;i++)
{
for(int j=0;j<=1+m;j++)
{
printf("%c",map[i][j]);
}
printf("\n");
}
}
int main()
{
for(int i=0;i<=9;i++)
{
map[i][0]='X';map[0][i]='X';
}
while(scanf("%d%d%d",&n,&m,&t),n,m,t)
{
int sx,sy;
int k=0;
ans=0;
memset(v,0,sizeof(v));
getchar();
for(int i=1;i<=n;i++)
{
for(int j=1;j<=m;j++)
{
scanf("%c",&map[i][j]);
if(map[i][j]=='X')k++;
if(map[i][j]=='D')
{
dx=i;dy=j;
}
if(map[i][j]=='S')
{
sx=i;sy=j;
v[i][j]=1;
}
}
getchar();
}
for(int i=0;i<=n;i++)
{
map[i][m+1]='X';
}
for(int i=0;i<=m;i++)
{
map[n+1][i]='X';
}
//p();
if(n*m-k-1>=t)dfs(0,sx,sy);
int temp=abs(sx-dx)+abs(sy-dy);
temp=t-temp;
if(temp&1)printf("NO\n");//奇偶剪枝
else if(ans)
printf("YES\n");
else printf("NO\n");
}
}
现假设起点为(sx,sy),终点为(ex,ey),给定t步恰好走到终点,
s | ||||
| | ||||
| | ||||
| | ||||
+ | — | — | — | e |