我只说一下别人讲的不清楚的,为什么一个点的某个方向不可以走两次?
实际上,这种说法和判断一个局面和前面重复是等价的。只不过后者是直观的说法,前者是一种“后知后觉”的说法,是建立在事情的结果上的,但是在这里,事情的结果显然具有更简单的情况,所以我们用事件的结果代表它本身。
比如如下三种情况:
可以很容易判断出来,他们是同一种情况,但是我们是怎么判断出来的,直觉?
用自然语言描述,就是说小人又可以把(4,3)点的箱子向左(右)推,注意这里一个“又”字,其实我们不自觉的就把判定方法建立在了结果之上,而不是这个局面本身,因为局面本身十分复杂,但结果只是这一个!所以即是说一个点的某方向不可以走两次。
广搜是无权图的最短路,如果我们可以在最短路中绕圈,则可以省去这个圈,与它是最短路矛盾,所以我们要判重!
最后它的最大地图是7*7,也就是49个格,如果存在一个解,显然最多是走遍每一个点的每个方向,一共49*4=196步,根据抽屉原理,最多在第197步会出现环路,这是不可能的,所以我们完全可以用unsigned char 存储步数。在此题表现的不是很明显,但是对于一些其他的,因为广搜几乎是指数爆炸式的增长数据,所以初始节点稍微改变一下条件,就可以在以后的以后刮起一场龙卷风!
#include <cstdio>
#include <cstring>
#include <queue>
struct point{
unsigned char x0,y0;
};
struct pro{
unsigned char x0,y0,x1,y1;
int step;
};
std::queue<point> q2;
std::queue<pro> q1;
int t,m,n,u1;
char map[10][10],dirr[10][10][4],temp[10][10],c[5];
char dir[4][2]={{0,1},{1,0},{-1,0},{0,-1}};
unsigned char h1,h2,flag;
bool path(point a,point b){
if((a.x0==b.x0)&&(a.y0==b.y0)) return true;
int i,j;
point p1,p2;
memcpy(temp,map,sizeof(map));
j=q2.size();
for(i=0;i<j;i++) q2.pop();
h1=a.x0;h2=a.y0;
p1.x0=h1;p1.y0=h2;
temp[h1][h2]=1;
q2.push(p1);j=0;
while(!q2.empty()){
p1=q2.front();
q2.pop();
for(i=0;i<4;i++){
h1=p1.x0+dir[i][0];
h2=p1.y0+dir[i][1];
if(temp[h1][h2]) continue;
p2.x0=h1;p2.y0=h2;
if((h1==b.x0)&&(h2==b.y0)) {j=1;return true;}
temp[h1][h2]=1;
q2.push(p2);
}
}
if(!j) return false;
return false;
}
point p1,p2,p3;
pro r1,r2,e;
int main(){
scanf("%d",&t);
while(t--){
memset(map,1,sizeof(map));
scanf("%d%d",&m,&n);
for(int i=1;i<=m;i++){
for(int j=1;j<=n;j++){
scanf("%s",c);
c[0]-='0';
if(*c==2) {r1.x0=i;r1.y0=j;}
else if(*c==3) {e.x0=i;e.y0=j;}
else if(*c==4) {r1.x1=i;r1.y1=j;}
if(*c>1) *c=0;
map[i][j]=*c;
}
}
memset(dirr,0,sizeof(dirr));
u1=q1.size();
for(int i=0;i<u1;i++) q1.pop();
r1.step=0;q1.push(r1);flag=0;
while(!q1.empty()){
r1=q1.front();
q1.pop();
map[r1.x0][r1.y0]=1;
p1.x0=r1.x1;p1.y0=r1.y1;
for(int i=0;i<4;i++){
p2.x0=r1.x0+dir[i][0];p2.y0=r1.y0+dir[i][1];
p3.x0=r1.x0+dir[3-i][0];p3.y0=r1.y0+dir[3-i][1];
if(map[p2.x0][p2.y0]||map[p3.x0][p3.y0]) continue;
if(path(p1,p2)){
if(p3.x0==e.x0&&p3.y0==e.y0){
flag=1;
printf("%d\n",r1.step+1);
break;
}
dirr[i][r1.x0][r1.y0]++;
if(dirr[i][r1.x0][r1.y0]==1){
r2.x0=p3.x0;r2.y0=p3.y0;r2.x1=r1.x0;r2.y1=r1.y0;r2.step=r1.step+1;
q1.push(r2);
}
}
}
if(flag) break;
map[r1.x0][r1.y0]=0;
}
if(flag) continue;
printf("-1\n");
}
return 0;
}