开始想着用广搜写写,后来想想感觉就是自己给自己找不自在,没法写。然后又开始用深搜来做,以前虽然学过深搜,但是好久没写,手很生,但是还是经过一番推理后写出来了,很开心。结果果断交上去就TLE了,后来想想应该可以剪枝吧,于是就剪枝,只是剪掉了输入的'.'少于那个规定时间t-1的情况,交上去又TEL了,剪得不够完美,准备继续剪,但是后来的剪枝结果证明都是不够完美的,于是果断百度了方法,发现了一种很神奇的方法就是奇偶剪枝,如下图
这就是传说中的奇偶剪枝,意思就是说1---1,0---0都是需要偶数步的,1---0,0---1都是需要奇数步的,这么就可以根据当前所剩步数的奇偶性跟当前位置和终点的奇偶性共同判断是否能走通。好深奥的说。
#include<stdio.h>
#include<iostream>
#include<string.h>
using namespace std;
char Map[10][10];
bool vis[10][10];
int f[4][2]= {{-1,0},{0,1},{1,0},{0,-1}};
int n,m,t;
bool flag1=0;
struct node
{
int x,y,value;
node()
{
x=1;
y=1;
value=1;
}
};
node a,b;
void init()
{
flag1=0;
for(int i=0; i<10; i++)
{
for(int j=0; j<10; j++)
{
vis[i][j]=0;
Map[i][j]='#';
}
}
a.value=t+1; //排除没起点的情况
}
bool dfs(node tmp)
{
bool flag,flag2;
if(tmp.value>t) //剪枝
return 0;
// cout<<"tmp "<<tmp.x<<" "<<tmp.y<<" "<<tmp.value<<endl;
if(tmp.x==b.x&&tmp.y==b.y&&tmp.value==t)
{
// cout<<"gg"<<endl;
return 1;
}
flag=(t-tmp.value)%2; //判断所剩步数的奇偶性
vis[tmp.x][tmp.y]=1; //标记走到当前位置
for(int i=0; i<4; i++)
{
a.x=tmp.x+f[i][0];
a.y=tmp.y+f[i][1];
a.value=tmp.value+1;
if(Map[a.x][a.y]!='X'&&a.x>=1&&a.y>=1&&a.x<=n&&a.y<=m&&vis[a.x][a.y]==0)
{
//递归的条件
// cout<<a.x<<" "<<a.y<<" "<<a.value<<endl;
flag2=(tmp.x+tmp.y)%2; //判断当前位置的奇偶性
if(flag2!=flag1&&flag==1||flag2==flag1&&flag==0)
{
//奇偶剪枝,如果满足当前位置跟终点位置奇偶性不同且所剩步数为奇
//或者当前位置跟终点位置奇偶性相同且所剩步数为偶就往下递归
// cout<<flag1<<"* "<<flag2<<"* "<<flag<<endl;
bool FG=0;
FG=dfs(a);
if(FG)
return 1;
}
}
}
vis[tmp.x][tmp.y]=0; //恢复标记
return 0;
}
int main()
{
while(scanf("%d%d%d",&n,&m,&t)!=EOF&&n!=0&&m!=0&&t!=0)
{
int num=0;
getchar();
init();
for(int i=1; i<=n; i++)
{
for(int j=1; j<=m; j++)
{
scanf("%c",&Map[i][j]);
if(Map[i][j]=='.')
{
num++;
}
else if(Map[i][j]=='S')
{
a.x=i;
a.y=j;
a.value=0;
}
else if(Map[i][j]=='D')
{
b.x=i;
b.y=j;
flag1=(i+j)%2; //判断终点的奇偶性
}
}
getchar();
}
if(num<t-1) //根据.的数量剪枝
{
printf("NO\n");
continue;
}
bool ans=dfs(a);
if(ans)
printf("YES\n");
else
printf("NO\n");
}
return 0;
}
/*
4 4 5
S.X.
..X.
.D..
XXXX
*/