超级迷宫 pku 3083 dfs+bfs 非常有意思的一道

http://acm.pku.edu.cn/JudgeOnline/problem?id=3083

 

神哪!!!昨天下午4点开始写 写到早上1.30...中间是第一次用Dev C++,有点系统小bug,搞了2小时.心灰意冷..结果写了9个小时还没写出来...今天去实训,回来后整理了下思路,找对了策略!对于左右手策略是这样的:如果左边(右边)有路左转(右转),否则向前,要是还不行,顺时针(逆时针)选择方向.因为设计了递归函数,所以理解起来很清晰~~但是当时怎么就没想到呢...想起小时候看过的一部电视剧<少年包青天>里面公孙策跟XX在迷失森林燕不归里找出路,其实他用的就是左右手规则中的一种,当时很小,理解不了,现在懂了.其实在图论里,也有类似的定理可以证明,具体么。。。哈哈 我用分治递归加剪枝做出来了!!

 

 

#include <stdio.h> #include <stdlib.h> #include <queue> using namespace std; #define max_size 41 char maze[max_size][max_size]; int path[max_size][max_size]; struct Grid{ int r; int c; Grid(int r = 0,int c = 0){ this->r = r; this->c = c; } Grid(const Grid & g){ this->r = g.r; this->c = g.c; } bool operator== (const Grid g){ return (r == g.r && c == g.c ? true : false); } bool operator!= (const Grid g){ return ((r != g.r || c != g.c) ? true : false); } }; Grid start,maze_exit; int h,w; /****************** * 0 * 3 1 * 2 *****************/ //逆时针贴着墙走。。。左旋方向 (i+3)%4 //四个方向向量 int dir[4][2] = {{-1,0},{0,1},{1,0},{0,-1}}; bool inside(Grid g){ return (g.r>=1 && g.r<=h && g.c>=1 && g.c<=w ? true : false); } //策略:始终贴着左手或者右手边的墙壁前进 /*贴着左手边的墙前进 void dfs(){ //需要保存当前的方向与位置 if(到终点) return; else{ if(左边有路) 左走; else if(前面有路) 直走; else 顺时针旋转方向 } dfs(); } */ bool headOK(Grid g,int d){ g.r += dir[d][0]; g.c += dir[d][1]; if(inside(g) && maze[g.r][g.c] != '#') return true; else return false; } bool leftOK(Grid g,int d){ int nd = (d + 3) % 4; g.r += dir[nd][0]; g.c += dir[nd][1]; if(inside(g) && maze[g.r][g.c] != '#') return true; else return false; } int head; int back; int right; int left; #define MAX_STEP 40 int PATH_LEFT; void dfs_left(Grid cur,int d){ //当前扩展结点,当前位置,当前方向 PATH_LEFT++; if(cur == maze_exit){ return ; } else{ Grid next; int nd; if(leftOK(cur,d)){ nd = (d + 3) % 4; next.r = cur.r + dir[nd][0]; next.c = cur.c + dir[nd][1]; //printf("left: %d (%d,%d)--->(%d,%d)/n",left++,cur.r,cur.c,next.r,next.c); } else if(headOK(cur,d)){ next.r = cur.r + dir[d][0]; next.c = cur.c + dir[d][1]; nd = d; //printf("head : %d (%d,%d) ===> (%d,%d)/n",head++,cur.r,cur.c,next.r,next.c); } else{ //顺时针旋转方向 next = cur; nd = d; while(1){ nd = (nd + 1) % 4; next.r = cur.r + dir[nd][0]; next.c = cur.c + dir[nd][1]; if(next != cur && inside(next) && maze[next.r][next.c] != '#') break; } //printf("顺时针旋转选择新的一格: (%d,%d)--->(%d,%d)/n",cur.r,cur.c,next.r,next.c); } dfs_left(next,nd); } } /*贴着右手的边前进 void dfs(){ if(到终点) return; else{ if(右边有路) 右走; else if(前面有路) 直走; else 逆时针选择方向; } dfs(); } */ bool rightOK(Grid g,int d){ int nd = (d + 1) % 4; g.r += dir[nd][0]; g.c += dir[nd][1]; if(inside(g) && maze[g.r][g.c] != '#') return true; else return false; } int PATH_RIGHT; void dfs_right(Grid cur,int d){ PATH_RIGHT++; if(cur == maze_exit){ return ; } else{ Grid next; int nd; if(rightOK(cur,d)){ nd = (d + 1) % 4; next.r = cur.r + dir[nd][0]; next.c = cur.c + dir[nd][1]; } else if(headOK(cur,d)){ next.r = cur.r + dir[d][0]; next.c = cur.c + dir[d][1]; nd = d; } else{ //逆时针旋转方向 next = cur; nd = d; while(1){ nd = (nd - 1 + 4) % 4; next.r = cur.r + dir[nd][0]; next.c = cur.c + dir[nd][1]; if(next != cur && inside(next) && maze[next.r][next.c] != '#') break; } } dfs_right(next,nd); } } void bfs(){ if(start == maze_exit){ path[start.r][start.c] = 1; return ; } Grid cur = start; Grid next; path[cur.r][cur.c] = 1; queue<Grid> q; while(true){ for(int k = 0;k < 4;k++){ next.r = cur.r + dir[k][0]; next.c = cur.c + dir[k][1]; if(inside(next) && maze[next.r][next.c] != '#' && !path[next.r][next.c]){ q.push(next); path[next.r][next.c] = path[cur.r][cur.c] + 1; if(next == maze_exit) break; } } if(next == maze_exit) break; if(q.empty()) break; cur = q.front(); q.pop(); } } int main(int argc, char *argv[]) { //freopen("input.txt","r",stdin); //freopen("output.txt","w",stdout); int num,i,j; scanf("%d",&num); while(num--){ scanf("%d%d/n",&w,&h); memset(maze,'/0',sizeof(maze)); memset(path,0,sizeof(path)); for(i = 1;i <= h;i++){ for(j = 1;j <= w;j++){ scanf("%c",&maze[i][j]); if(maze[i][j] == 'S'){ start.r = i; start.c = j; } else if(maze[i][j] == 'E'){ maze_exit.r = i; maze_exit.c = j; } } char ch; scanf("%c",&ch); } /* for(i = 1;i <= h;i++){ for(j = 1;j <= w;j++) printf("%c",maze[i][j]); printf("/n"); } */ /****************** * 0 * 3 1 * 2 *****************/ head = back = right = left = 1; PATH_LEFT = 0; PATH_RIGHT = 0; if(start.r == 1){ dfs_left(start,2); dfs_right(start,2); } else if(start.r == h){ dfs_left(start,0); dfs_right(start,0); } else if(start.c == 1){ dfs_left(start,1); dfs_right(start,1); } else{ dfs_left(start,3); dfs_right(start,3); } printf("%d %d ",PATH_LEFT,PATH_RIGHT); bfs(); printf("%d/n",path[maze_exit.r][maze_exit.c]); } system("PAUSE"); return 0; }

你可能感兴趣的:(超级迷宫 pku 3083 dfs+bfs 非常有意思的一道)