题意:
n*m的矩阵,S是出发点,D是终点,
.是可以走的,X是不可以走的,T秒的时候D
才会被打开,否则就出不去,输出doggie最
后能否出去。
分析:奇偶剪枝
这个题目用一般的搜索无法完成,因为题目
要求在指定的时间内完成,所以只好一步一
步来啦,用DFS解决
但是如果直接用dfs结果会超时,网上说是用
一种奇偶剪枝的方法来间断搜索时间,
下面是剪枝的简单理论:
把map看作
0 1 0 1 0 1
1 0 1 0 1 0
0 1 0 1 0 1
1 0 1 0 1 0
0 1 0 1 0 1
从 0->1 需要奇数步
从 0->0 需要偶数步
那么设所在位置 (x,y) 与目标位置 (dx,dy)
如果abs(x-y)+abs(dx-dy)为偶数,则说明 abs(x-y) 和 abs(dx-dy)的奇偶性相同,需要走偶数步
如果abs(x-y)+abs(dx-dy)为奇数,那么说明 abs(x-y) 和 abs(dx-dy)的奇偶性不同,需要走奇数步
理解为 abs(si-sj)+abs(di-dj) 的奇偶性就确定了所需要的步数的奇偶性!!
而 (ti-setp)表示剩下还需要走的步数,由于题目要求要在 ti时恰好到达,
那么 (ti-step) 与abs(x-y)+abs(dx-dy) 的奇偶性必须相同
因此 temp=ti-step-abs(dx-x)-abs(dy-y) 必然为偶数!
一般这种dfs题目都需要一个map[][]记录个点的值,
一个record[][]记录一下某点是否走过(防止走重!!)
一个用于检测是否越界的函数isin()
其余的就是dfs函数的设计了。
//不知道我的代码哪里错了。。。就是wa了
#include <iostream>
#include <cstdio>
#include <cstring>
#include <cmath>
#include <algorithm>
using namespace std;
const int maxn=10;
int n,m,t,cnt,sx,sy,gx,gy;
int dx[4]= {-1,0,0,1},dy[4]= {0,1,-1,0};
char mp[maxn][maxn];
int visit[maxn][maxn];
bool dfs(int x,int y,int cnt)
{
int i,j,nx,ny;
if(cnt==t&&mp[x][y]=='D')
return true;
if(x<1||x>n|y<1||y>m)
return false;
if(cnt>=t)
return false;
if(t-cnt<(abs(x-gx)+abs(y-gy)))
return false;
if((t-cnt-(int)(abs(x-gx)+abs(y-gy)))%2!=0)
return false;
//visit[x][y]=1;
for(i=0; i<4; i++)
{
nx=x+dx[i];
ny=y+dy[i];
if(nx>=1&&nx<=n&&ny>=1&&ny<=m&&!visit[nx][ny]&&mp[nx][ny]!='X')
{
visit[nx][ny]=1;
if(dfs(nx,ny,cnt+1))//看看如果走这条路是否能走出去(true)
return true;
else
visit[nx][ny]=0;//不能走出去的话就尝试下一种方式,就算是没走过这条路,故visit要标记成0,以免影响下一次的访问
}
}
return false;
}
int main()
{
freopen("in.txt","r",stdin);
while((scanf("%d%d%d",&n,&m,&t)!=EOF)&&(n||m||t))
{
memset(visit,0,sizeof(visit));
int i,j;
for(i=1; i<=n; i++)
{
getchar();
for(j=1; j<=m; j++)
{
scanf("%c",&mp[i][j]);
if(mp[i][j]=='S')
{
sx=i;
sy=j;
}
if(mp[i][j]=='D')
{
gx=i;
gy=j;
}
}
}
visit[sx][sy]=1;
if(dfs(sx,sy,0))
printf("YES\n");
else
printf("NO\n");
}
return 0;
}
//AC代码:这是参考了别人的代码后来改过的。。。orz
#include<iostream>
#include<cmath>
#include<cstring>
#include<queue>
#include <cstdio>
int fangxiang[4][2]={{-1,0},{1,0},{0,-1},{0,1}};
const int MAX=101;
char map[MAX][MAX];
int mark[MAX][MAX];
int n,m,t;
int start_x,start_y;
int end_x,end_y;
using namespace std;
bool DFS(int x,int y,int step)
{
int i,a,b;
if(map[x][y]=='D'&&step==t)
return true;
if(x<1||x>n|y<1||y>m)
return false;
if(step>=t)//剪枝1:当step>=T时还没有找到D点
return false;
if(t-step<(abs(x-end_x)+abs(y-end_y)))//剪枝2:还需要的步数比理论上的最短距离还小
return false;
if((t-step-(int)(abs(x-end_x)+abs(y-end_y)))%2!=0) //剪枝3:比理论上的最短距离多出来的必是偶数
return false;
for(i=0;i<4;i++)
{
a=x+fangxiang[i][0];
b=y+fangxiang[i][1];
if(a<=n&&a>=1&&b>=1&&b<=m&&map[a][b]!='X'&&!mark[a][b]) //判断三个条件:1.检验_x,_y是否越界。2.看vis[][]是否访问过。3.看map[][]是否是墙
{
mark[a][b]=1;
if(DFS(a,b,step+1))
return true;
else
mark[a][b]=0;
}
}
return false;
}
int main()
{
//freopen("in.txt","r",stdin);
int i,j;
while(cin>>n>>m>>t&&(n||m||t))
{
memset(mark,0,sizeof(mark));
for(i=1;i<=n;i++)
{
for(j=1;j<=m;j++)
{
cin>>map[i][j];
if(map[i][j]=='S')
{
start_x=i;
start_y=j;
}
if(map[i][j]=='D')
{
end_x=i;
end_y=j;
}
}
}
mark[start_x][start_y]=1;
if(DFS(start_x,start_y,0))
cout<<"YES"<<endl;
else
cout<<"NO"<<endl;
}
return 0;
}