手机的诱惑
题目大意:
给你一个N*M(1<N,M<7)的字符矩阵,其中包含字符含义:
‘X’:不能进入的墙
‘S’:起点
‘D’:门
‘.’:可以行走的地方问:若每个点只能走一次,每次只能走上下左右4个方向,从起点到门的是否存在长度恰好为T(0<T<50)的路径?
用例输入
4 4 5 S.X. ..X. ..XD .... 3 4 5 S.X. ..X. ...D 0 0 0
用例输出
NO YES
思路
bfs不太适合:bfs会先考虑周围的点,逐步进行“扩散”搜索,不能直接“绕远路”,求恰好长度为T的路径可能会“绕远路”,不能穷举所有情况。故采用dfs。
奇偶性剪枝:直接写dfs还是会TLE(原来没想到这玩意儿,尝试剪枝了无数次,同时TLE了无数次,我服了),所以要用到一个很重要的奇偶性剪枝。
考虑两个点:p1:(x1,y1),p2:(x2,y2),则从p1到p2的路径长度的奇偶性与两坐标的奇偶性有关,若(x1+y1)%2==(x2+y2)%2,则p1到p2无论怎么走,路径长度都是偶数,反之都是奇数。
举个例子,拿最简单的相邻的两个点来说,路径长度为1,无论怎么走,路径长度都是奇数,因为他们各自的横纵坐标之和的奇偶性不一样。
代码
#include<bits/stdc++.h>
using namespace std;
int n,m,t;
char mp[10][10];
bool st[10][10];
int ans;
int sta_x,sta_y;
int ed_x,ed_y;
int dfs(int d,int x,int y)
{
if(d==t)return mp[x][y]=='D'?1:0;
if(mp[x][y]=='D')
{
return d==t?1:0;
}
if(((x+y)%2+(ed_x+ed_y)%2)%2!=abs(d-t)%2)//矩阵奇偶性优化
{
return 0;
}
int dx[4]={0,0,1,-1};
int dy[4]={1,-1,0,0};
int res=0;
for(int i=0;i<4;i++)
{
int xx=x+dx[i];
int yy=y+dy[i];
if(xx>=0&&yy>=0&&xx<n&&yy<m&&mp[xx][yy]!='X'&&!st[xx][yy])
{
st[xx][yy]=1;
if(dfs(d+1,xx,yy))return 1;
st[xx][yy]=0;
}
}
return 0;
}
void solve()
{
ans=0;
memset(st,0,sizeof st);
for(int i=0;i<n;i++)
cin>>mp[i];
for(int i=0;i<n;i++)
{
for(int j=0;j<m;j++)
{
if(mp[i][j]=='S')
sta_x=i,sta_y=j;
if(mp[i][j]=='D')
ed_x=i,ed_y=j;
}
}
st[sta_x][sta_y]=1;
ans=dfs(0,sta_x,sta_y);
if(ans)
cout<<"YES"<<endl;
else cout<<"NO"<<endl;
}
int main()
{
while(cin>>n>>m>>t,n,m,t)
solve();
}