杭电1728————一直WA的BFS(有思维惯性带来的陷阱)
来源:互联网 发布:手机破解压缩文件软件 编辑:程序博客网 时间:2024/05/01 07:11
逃离迷宫
Time Limit: 1000/1000 MS (Java/Others) Memory Limit: 32768/32768 K (Java/Others)Total Submission(s): 15281 Accepted Submission(s): 3692
Problem Description
给定一个m × n (m行, n列)的迷宫,迷宫中有两个位置,gloria想从迷宫的一个位置走到另外一个位置,当然迷宫中有些地方是空地,gloria可以穿越,有些地方是障碍,她必须绕行,从迷宫的一个位置,只能走到与它相邻的4个位置中,当然在行走过程中,gloria不能走到迷宫外面去。令人头痛的是,gloria是个没什么方向感的人,因此,她在行走过程中,不能转太多弯了,否则她会晕倒的。我们假定给定的两个位置都是空地,初始时,gloria所面向的方向未定,她可以选择4个方向的任何一个出发,而不算成一次转弯。gloria能从一个位置走到另外一个位置吗?
Input
第1行为一个整数t (1 ≤ t ≤ 100),表示测试数据的个数,接下来为t组测试数据,每组测试数据中,
第1行为两个整数m, n (1 ≤ m, n ≤ 100),分别表示迷宫的行数和列数,接下来m行,每行包括n个字符,其中字符'.'表示该位置为空地,字符'*'表示该位置为障碍,输入数据中只有这两种字符,每组测试数据的最后一行为5个整数k, x1, y1, x2, y2 (1 ≤ k ≤ 10, 1 ≤ x1, x2 ≤ n, 1 ≤ y1, y2 ≤ m),其中k表示gloria最多能转的弯数,(x1, y1), (x2, y2)表示两个位置,其中x1,x2对应列,y1, y2对应行。
第1行为两个整数m, n (1 ≤ m, n ≤ 100),分别表示迷宫的行数和列数,接下来m行,每行包括n个字符,其中字符'.'表示该位置为空地,字符'*'表示该位置为障碍,输入数据中只有这两种字符,每组测试数据的最后一行为5个整数k, x1, y1, x2, y2 (1 ≤ k ≤ 10, 1 ≤ x1, x2 ≤ n, 1 ≤ y1, y2 ≤ m),其中k表示gloria最多能转的弯数,(x1, y1), (x2, y2)表示两个位置,其中x1,x2对应列,y1, y2对应行。
Output
每组测试数据对应为一行,若gloria能从一个位置走到另外一个位置,输出“yes”,否则输出“no”。
Sample Input
25 5...***.**...........*....1 1 1 1 35 5...***.**...........*....2 1 1 1 3
Sample Output
noyes
Source
“网新恩普杯”杭州电子科技大学程序设计邀请赛
一开我就很单纯的以为是BFS+一些前驱的小应用而已....写下了如下代码过了很多组测试数据不断WA OTZ
<span style="font-family:Microsoft YaHei;font-size:14px;">#include <cstdio>#include <cstring>#include <queue>#define maxn 105using namespace std;/*到达的时候转弯数小于maxturn就行*/ struct point{ int x,y; int turn;/*转弯个数*/ int turnx,turny;/*记录向哪转的方向*/ };int dx[4] = {1,-1,0,0},dy[4] = {0,0,1,-1};int row,col;int maze[maxn][maxn];int vis[maxn][maxn];int maxturn,sx,sy,ex,ey;/*start_x,start_y,end_x,end_y*/int find;queue<struct point> Q;void read_maze(){ char str[maxn]; memset(vis,0,sizeof(vis)); getchar(); for(int i = 1 ; i <= row ; i++) { scanf("%s",str); for(int j = 0 ; j < strlen(str) ; j++) { if(str[j] == '*') maze[i][j+1] = 1; else maze[i][j+1] = 0; } getchar(); } scanf("%d",&maxturn); scanf("%d%d%d%d",&sy,&sx,&ey,&ex);}int inborder(int x,int y){ int flag = 1; if(x < 1 || x > row || y < 1 || y > col) flag = 0; if(maze[x][y] == 1) flag = 0; return flag;}void BFS(){ struct point now,next; while(!Q.empty()) Q.pop();/*每次搜索前清空队列*/ now.x = sx; now.y = sy; now.turn = 0; now.turnx = 0; now.turny = 0; vis[sx][sy] = 1; Q.push(now); while(!Q.empty()) { now = Q.front(); Q.pop(); for(int k = 0 ; k < 4 ; k++) { next.x = now.x + dx[k]; next.turnx = dx[k]; next.y = now.y + dy[k]; next.turny = dy[k]; if(inborder(next.x,next.y) && !vis[next.x][next.y]) { vis[next.x][next.y] = 1; if(next.turnx == now.turnx && next.turny == now.turny) /*和之前走的方向不一致也就是说转弯了*/ next.turn = now.turn; else next.turn = now.turn + 1; Q.push(next); if(next.x == ex && next.y == ey && next.turn > maxturn + 1) { find = 0; return ; } if(next.x == ex && next.y == ey && next.turn <= maxturn + 1) { find = 1; return ; } } } } }int main(){ int T; scanf("%d",&T); while(T--) { scanf("%d%d",&row,&col); read_maze();/*经测试正确*/ find = 0;/*默认找不到*/ BFS(); if(find) printf("yes\n"); else printf("no\n"); } return 0;}</span>无限WA是什么情况...想不明白想不明白..(陷入思维定式了肯定想不明白)
只好百度了.....看到了一个AC代码,竟然没有vis数组进行标记,但是作者也没说为什么。又看了一下别人的,大致有了了解。
如图所示:
假设4是目标位置。
假设在2这个坐标转弯数是5,是向下走的,那么4的转弯数是5
假设在3这个坐标转弯数是5,是向下走的,那么4的转弯数就是6
2 . 3 这两个点很明显都是4的上一层(从搜索树来看)但是如果3比2先入队,那么3就先出队列,把4遍历过,4的转弯数就是6了,并且把4标记为已经遍历,那么2后出队就无法遍历4,但是按照假设很显然从2到4的转弯数最少
所以新建一个moveto[i][j]数组表示到达i,j坐标的最小转弯数(初始化为一个很大的数)
<span style="font-family:Microsoft YaHei;font-size:14px;">when moveto[i][j] >= 下一入队结点的转弯数{moveto[i][j] = 下一结点转弯数;下一结点入队;}</span>
亲测46MS
<span style="font-family:Microsoft YaHei;font-size:14px;">#include <cstdio>#include <cstring>#include <queue>#define maxn 105using namespace std;/*到达的时候转弯数小于maxturn就行*/ struct point{int x,y;int turn;/*转弯个数*/ int dir;};int dir[4][2] = {{0,1},{-1,0},{1,0},{0,-1}};int row,col;int maze[maxn][maxn];int moveto[maxn][maxn];/*记录了移动到(i,j)处需要的转弯数*/ int maxturn,sx,sy,ex,ey;/*start_x,start_y,end_x,end_y*/int find;queue<struct point> Q;void read_maze(){char str[maxn];for(int i = 0 ; i <= row ; i++)for(int j = 0 ; j <= col ; j++)moveto[i][j] = 10000;getchar();for(int i = 1 ; i <= row ; i++){scanf("%s",str);for(int j = 0 ; j < strlen(str) ; j++){if(str[j] == '*')maze[i][j+1] = 1;elsemaze[i][j+1] = 0;}getchar();}scanf("%d",&maxturn);scanf("%d%d%d%d",&sy,&sx,&ey,&ex);}int inborder(int x,int y){int flag = 1; if(x < 1 || x > row || y < 1 || y > col)flag = 0;if(maze[x][y] == 1)flag = 0;return flag;}void BFS(){struct point pre,next;while(!Q.empty())Q.pop();/*每次搜索前清空队列*/pre.x = sx;pre.y = sy;pre.turn = 0;pre.dir = -1;/*第一次移动不算转弯*/ moveto[sx][sy] = 0;/*初始化转弯数为0*/ Q.push(pre);while(!Q.empty()){pre = Q.front();Q.pop();for(int k = 0 ; k < 4 ; k++){next = pre;next.x += dir[k][0];next.y += dir[k][1];if(!inborder(next.x,next.y))continue;if(next.dir != k && next.dir != -1)/*==-1是初始点不用算转弯数*/ next.turn ++;/*相当于next.turn = pre.turn + 1;*/ if(next.turn > maxturn)continue;if(moveto[next.x][next.y] >= next.turn){next.dir = k;/*前边的判断全部是否定的说明是没有转弯的*/ moveto[next.x][next.y] = next.turn;Q.push(next);}if(next.x == ex && next.y == ey){find = 1;return ;}}} }int main(){int T;scanf("%d",&T);while(T--){scanf("%d%d",&row,&col);read_maze();/*经测试正确*/ find = 0;/*默认找不到*/if(sx == ex && sy == ey)printf("yes\n");else{BFS();if(find)printf("yes\n");elseprintf("no\n");}}return 0;}</span>
0 0
- 杭电1728————一直WA的BFS(有思维惯性带来的陷阱)
- hdu1010—我的惯性思维
- 打破惯性思维的限制——职场人士寓言(9)
- 我的思维惯性
- 思维的惯性
- 人的惯性思维
- 杭电ACM1240——Asteroids!~~简单的BFS
- 程序员的几个思维惯性
- bfs加条件的移动以及三个起点(难题;一直wa)
- uvaoj10341(详解 + 一直WA的,快来看看)
- 杭电1180——诡异的楼梯(BFS+优先队列)
- 成长的路上一直有你——英语
- HDU 5353 Average(这里或许有你一直WA的原因)
- 陷入思维陷阱(2)——解脱出来
- Java程序员惯性思维的一个错误
- Java程序员惯性思维的一个错误
- 思维惯性引发的编程问题
- 小心,分析问题时的思维惯性
- 网络相关配置文件
- hdu 4006 The kth great number (优先队列+STB+最小堆)
- 升级Android L完后,打开项目出现'load data for Android L(preview)'has encountered a problem.
- 拓展欧几里得临时文档5
- [Linux]很方便的上传下载文件工具rz和sz
- 杭电1728————一直WA的BFS(有思维惯性带来的陷阱)
- 网络测试命令
- Oracle之触发器 函数
- 在 Mac OS X 终端里使用 Solarized 配色方案
- java wait()方法notifyAll()方法实现三个线程打印A,B,C字符
- IE6 PNG透明终极解决方案
- ffmpeg解复用视频文件
- C语言可变参数宏定义方法
- 怎么会有种新车报废的感觉 粉红色奥拓报废之旅