hdoj 2364 Escape(BFS)

来源:互联网 发布:多玩永恒之塔数据库 编辑:程序博客网 时间:2024/05/18 00:57

开始没想到用三维数组存方向,用DFS写,,一直WA,后来想到哪里出错后改对了,,终于TLE,心满意足地重新用BFS敲一遍。。。T T


Escape

Time Limit: 1000/1000 MS (Java/Others)    Memory Limit: 32768/32768 K (Java/Others)
Total Submission(s): 658    Accepted Submission(s): 266


Problem Description
You find yourself trapped in a large rectangular room, made up of large square tiles; some are accessible, others are blocked by obstacles or walls. With a single step, you can move from one tile to another tile if it is horizontally or vertically adjacent (i.e. you cannot move diagonally).
To shake off any people following you, you do not want to move in a straight line. In fact, you want to take a turn at every opportunity, never moving in any single direction longer than strictly necessary. This means that if, for example, you enter a tile from the south, you will turn either left or right, leaving to the west or the east. Only if both directions are blocked, will you move on straight ahead. You never turn around and go back!
Given a map of the room and your starting location, figure out how long it will take you to escape (that is: reach the edge of the room).


 

Input
On the first line an integer t (1 <= t <= 100): the number of test cases. Then for each test case:

a line with two integers separated by a space, h and w (1 <= h, w <= 80), the height and width of the room;

then h lines, each containing w characters, describing the room. Each character is one of . (period; an accessible space), # (a blocked space) or @ (your starting location).
There will be exactly one @ character in each room description.
 

Output
For each test case:

A line with an integer: the minimal number of steps necessary to reach the edge of the room, or -1 if no escape is possible.
 

Sample Input
29 13##############@..........######.#.#.#.##...........##.#.#.#.#.#.##.#.......#.##.#.#.#.#.#.##...........######.#######4 6#.#####.#.###...@#######
 

Sample Output
31-1
 

Source
bapc2007_pre
 

题目大意:从@点出发,每一步如果可以向左或者向右移动,就向左或右移,除非两个方向都不能移动,才继续直走。而且如果走出就不能回头。问到达边界的最短时间。
解题思路:这题的难点在于方向的转化,因为人是在移动,所以他的方向不仅仅是地图上的上下左右,所以我们要记录他面朝的方向。
                  另一个难点是左右前的移动关系,它们并不是并列的,我们可以加一个flag标记,如果左右可以移动,就跳过直走的。
                   对于状态表示,我们可以用三维数组实现,vis[x][y][dir],注意还有一个坑就是如果起始位置就在边界,那么就不需要移动,直接输出0就好。

同样给出几组样例供测试。

#include<iostream>#include<cstdio>#include<cstring>#include<queue>using namespace std;const int N = 100;struct Point{    int x, y;    int dir;    int step;}start, fr, next;char mp[N][N];int vis[N][N][4];int dirr[4][2] = {-1, 0, 0, 1, 1, 0, 0, -1};int n, m;void bfs(){    queue<Point> Q;    Q.push(start);    while(!Q.empty()){        fr = Q.front();       // cout << fr.x << " " << fr.y << endl;        Q.pop();        if((fr.x == 1 || fr.x == n || fr.y == 1 || fr.y == m) && mp[fr.x][fr.y] == '.'){            printf("%d\n", fr.step);            return;        }        int d, flag = 0;        for(int i = 0; i < 4; i++){            if(fr.dir == -1) d = i;            else switch(i){                case 1: if(fr.dir % 2 == 0) d = 1; else d = 0; break;                case 2: d += 2; break;                case 3: d = fr.dir; break;                default: continue; break;            }            if(flag && d == fr.dir) continue;            next.x = fr.x + dirr[d][0];            next.y = fr.y + dirr[d][1];            next.dir = d;            if(mp[next.x][next.y] == '#' || mp[next.x][next.y] == '\0') continue;            flag = 1;            if(!vis[next.x][next.y][next.dir]){                vis[next.x][next.y][next.dir] = 1;                next.step = fr.step + 1;                Q.push(next);            }        }    }    puts("-1");    return;}int main(){    int T;    scanf("%d", &T);    while(T--){        memset(mp, '\0', sizeof(mp));        scanf("%d%d", &n, &m);        for(int i = 1; i <= n; i++){            scanf("%s", mp[i] + 1);            for(int j = 1; j <= m; j++)            if(mp[i][j] == '@'){                start.x = i;                start.y = j;                start.dir = -1;                start.step = 0;            }        }        if(start.x == 1 || start.x == n || start.y == 1 || start.y == m){            puts("0");            continue;        }        memset(vis, 0, sizeof(vis));        for(int i = 0; i < 4; i++) vis[start.x][start.y][i] = 1;        bfs();    }    return 0;}/*205 7###.######...##@..#.####...########4 5.#####@...#...##.###5 5#...#.#.#..@....#.#.#...#7 6##.#####.#####..####.###..@...##.#####.###9 13##############@..........######.#.#.#.##...........##.#.#.#.#.#.##.#.......#.#..#.#.#.#.#.##...........##############5 5............@............*/


0 0