0
题目:
题意很清晰,注意走过一个地方就不能再走(所以可以根据这一点,预先筛选掉很多随机数据文件,看code最后一个注释的地方),还要注意是恰好那个时间到达,所以要有足够的地方腾挪(结合刚才那一点因此多了一个预先筛选这样一个剪枝的手段。)
1
分析:
主要学习奇偶剪枝和预先筛选的思想。
补充,奇偶剪枝(摘自百度百科):
现假设起点为(sx,sy),终点为(ex,ey),给定t步恰好走到终点,
s
| ||||
|
| ||||
|
| ||||
|
| ||||
+
|
—
|
—
|
—
|
e
|
如图所示(“|”竖走,“—”横走,“+”转弯),易证abs(ex-sx)+abs(ey-sy)为此问题类中任意情况下,起点到终点的最短步数,记做step,此处step1=8;
s
|
—
|
—
|
—
| |
—
|
—
|
+
| ||
|
|
+
| |||
|
| ||||
+
|
—
|
—
|
—
|
e
|
如图,为一般情况下非
最短路径的任意走法举例,step2=14;
step2-step1=6,偏移路径为6,偶数(易证);
即,不论怎么走,其走的步数和最短的步数的
2
#include <iostream>
#include <string>
#include <algorithm>
#include <string.h>
#include <math.h>
#include <stdio.h>
using namespace std;
char mat[8][8];
int visted[8][8];
struct points{
int x;
int y;
bool operator ==(points& rhs) const{
return (x==rhs.x&&y==rhs.y);
}
}star,endd,cur,t1,t2;
int n;int m;int t;
int flag;
int wall;
int dir[4][2]={{-1,0},{1,0},{0,1},{0,-1}};
void Dfs(struct points cur,int time){
if(time==t){
return ;
}
int val=(t-time)-(abs(endd.x-cur.x)+abs(endd.y-cur.y));
if(val&1||val<0){///奇偶剪枝,val&1即val是奇数(&按位&,相同为1,不同为0)。
return;
}
struct points next;
for(int i=0;i<4;i++){
next.x=cur.x+dir[i][0];
next.y=cur.y+dir[i][1];
if(next.x<1||next.x>n||next.y<1||next.y>m) continue;
if(next==endd&&time+1==t){
flag=1;
return ;
}
if(mat[next.x][next.y]=='.'){
mat[next.x][next.y]='X';
Dfs(next,time+1);
mat[next.x][next.y]='.';
}
if(flag==1){
return ;
}
}
return ;
}
int main(){
while(~scanf("%d%d%d",&n,&m,&t)&&n!=0){
flag=0;
wall=0;
for(int i=1;i<=n;i++){
for(int j=1;j<=m;j++){
cin>>mat[i][j];
visted[i][j]=0;
if(mat[i][j]=='S') {
star.x=i;
star.y=j;
}
if(mat[i][j]=='X'){
wall++;
}
if(mat[i][j]=='D'){
endd.x=i;
endd.y=j;
}
}
}
if((n*m-wall)<=t){///注意!!,因为数据是在卡定范围下随机的,所以理应想到,如果该题允许无解的情况,就很可能有很多大数的数据文件都是如此,所以想办法进入DFS前就去掉他们。这里去掉的是,没有多余地方可供腾挪的,因为题意明确指出每一个地方只能到一次。(另外,注意我尝试去掉=,会慢几百ms,所以很多数据的个数都应该是卡在了n*m-wall==t这个点了,之前还以为算法有问题查了好久、)
cout<<"NO"<<endl;
continue;
}
Dfs(star,0);
if(flag==1){
cout<<"YES"<<endl;
}
else{
cout<<"NO"<<endl;
}
}
}