Sicily 9017. Amazing Mazes

来源:互联网 发布:蜂窝移动数据是什么 编辑:程序博客网 时间:2024/06/05 16:02

9017. Amazing Mazes

Constraints

Time Limit: 1 secs, Memory Limit: 256 MB

Description

You are requested to solve maze problems. Without passing through these mazes, you might not be able to pass through the domestic contest!

A maze here is a rectangular area of a number of squares, lined up both lengthwise and widthwise, The area is surrounded by walls except for its entry and exit. The entry to the maze is at the leftmost part of the upper side of the rectangular area, that is, the upper side of the uppermost leftmost square of the maze is open. The exit is located at the rightmost part of the lower side, likewise.

In the maze, you can move from a square to one of the squares adjoining either horizontally or vertically. Adjoining squares, however, may be separated by a wall, and when they are, you cannot go through the wall.

Your task is to find the length of the shortest path from the entry to the exit. Note that there may be more than one shortest paths, or there may be none.

Input

 

The input consists of one or more datasets, each of which represents a maze.

The first line of a dataset contains two integer numbers, the width w and the height h of the rectangular area, in this order.

 The following 2 × h ? 1 lines of a dataset describe whether there are walls between squares or not. The first line starts with a space and the rest of the line contains w ? 1 integers, 1 or 0, separated by a space. These indicate whether walls separate horizontally adjoining squares in the first row. An integer 1 indicates a wall is placed, and 0 indicates no wall is there. The second line starts without a space and contains w integers, 1 or 0, separated by a space. These indicate whether walls separate vertically adjoining squares in the first and the second rows. An integer 1/0 indicates a wall is placed or not. The following lines indicate placing of walls between horizontally and vertically adjoining squares, alternately, in the same manner.

The end of the input is indicated by a line containing two zeros.

The number of datasets is no more than 100. Both the widths and the heights of rectangular areas are no less than 2 and no more than 30.

Output

For each dataset, output a line having an integer indicating the
length of the shortest path from the entry to the exit. The length of
a path is given by the number of visited squares. If there exists
no path to go through the maze, output a line containing a single
zero. The line should not contain any character other than this
number.

Sample Input

2 3 10 1 01 0 19 4 1 0 1 0 0 0 0 00 1 1 0 1 1 0 0 0 1 0 1 1 0 0 0 00 0 0 0 0 0 0 1 1 0 0 0 1 0 0 1 10 0 0 0 1 1 0 0 0 0 0 0 0 0 0 1 012 5 1 0 0 0 0 0 0 0 0 0 00 0 0 1 1 0 0 0 0 0 0 0 1 0 1 0 0 0 0 0 0 0 00 0 0 0 0 0 1 1 0 0 0 0 0 0 1 0 0 1 0 1 0 0 00 0 0 1 1 0 1 1 0 1 1 0 0 0 0 0 0 1 0 0 1 0 00 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 0 00 0

Sample Output

4020

Problem Source

2013年每周一赛第八场 Asia Regional Contest 2010 in Tokyo

走迷宫,bfs,这里的建图好麻烦;

建图步骤:

首先要知道,题目中的01单数行表示的是格子,偶数行表示的是墙壁,比如把题目中第三个样例的图建出来看看:


void make_map(int w, int h) {    int i, j;    memset(map, 0, sizeof(map));       for (i = 0; i <= 2 * h; i++) {        if (i == 0 || i == 2 * h) {            for (j = 0; j <= 2 * w; j++) {                map[i][j] = 1;            }        } else {            map[i][0] = map[i][2 * w] = 1;        }    }    map[0][1] = map[2 * h][2 * w - 1] = 0;       for (i = 1; i <= 2 * h - 1; i++) {        if (i % 2 == 1) {            for (j = 0; j < w - 1; j++) {                scanf("%d", &map[i][2 * j + 2]);            }        } else {            for (j = 0; j < w; j++) {                scanf("%d", &map[i][2 * j + 1]);            }        }    }    //以下就是添砖加瓦部分,注意添砖加瓦只在墙壁行中执行    for (i = 2; i < 2 * h; i += 2) {//i保持是偶数,保证修改的是墙壁而不是格子        for (j = 1; j < 2 * w; j++) {//两道墙壁中的链接点也设为墙壁            if (map[i - 1][j] == 1 && map[i + 1][j] == 1)                map[i][j] = 1;            if (map[i][j - 1] == 1 && map[i][j + 1] == 1)                map[i][j] = 1;        }    }    for (i = 2; i < 2 * h; i += 2) {//把墙角设为墙壁        for (j = 1; j < 2 * w; j++) {            if (map[i - 1][j] == 1 && map[i][j - 1] == 1)                map[i][j] = 1;            if (map[i + 1][j] == 1 && map[i][j - 1] == 1)                map[i][j] = 1;            if (map[i - 1][j] == 1 && map[i][j + 1] == 1)                map[i][j] = 1;            if (map[i + 1][j] == 1 && map[i][j + 1] == 1)                map[i][j] = 1;        }    }    //以上就是添砖加瓦部分    exit_i = 2 * h - 1;    exit_j = 2 * w - 1;}
当去除了添砖加瓦后:

 有点难以看懂对吧,但是这样才是正确的,这样看起来好像会难走,但实际上bfs的时候由于条件的设置足够ok因此是没有问题的,就算是有些墙有个小洞,但是由于我们走的时候是两格两格走的,所以没有影响;

ok,贴上第一次提交的代码(0.11s):

#include <iostream>#include <string.h>#include <vector>#include <queue>#include <stdio.h>using namespace std;#define INF 100000000int w, h;//宽高int map[65][65], exit_i, exit_j;//构建图形以及终点的ij坐标int dist[65][65];//图形中各个点离起点的距离int to_i[4] = {0, 2, 0, -2};//移动方向int to_j[4] = {2, 0, -2, 0};typedef pair<int, int> P;//记录点移动void make_map(int w, int h) {//构建地图    int i, j;    memset(map, 0, sizeof(map));       for (i = 0; i <= 2 * h; i++) {        if (i == 0 || i == 2 * h) {//上下边界            for (j = 0; j <= 2 * w; j++) {                map[i][j] = 1;            }        } else {            map[i][0] = map[i][2 * w] = 1;//左右边界        }    }       map[0][1] = map[2 * h][2 * w - 1] = 0;//开口,注意这个不要也行,起点不是这个       for (i = 1; i <= 2 * h - 1; i++) {        if (i % 2 == 1) {//奇数行为实际格子            for (j = 0; j < w - 1; j++) {                scanf("%d", &map[i][2 * j + 2]);            }        } else {//偶数行为墙壁            for (j = 0; j < w; j++) {                scanf("%d", &map[i][2 * j + 1]);            }        }    }       /*for (i = 2; i < 2 * h; i += 2) {        for (j = 1; j < 2 * w; j++) {            if (map[i - 1][j] == 1 && map[i + 1][j] == 1)                map[i][j] = 1;            if (map[i][j - 1] == 1 && map[i][j + 1] == 1)                map[i][j] = 1;        }    }    for (i = 2; i < 2 * h; i += 2) {        for (j = 1; j < 2 * w; j++) {            if (map[i - 1][j] == 1 && map[i][j - 1] == 1)                map[i][j] = 1;            if (map[i + 1][j] == 1 && map[i][j - 1] == 1)                map[i][j] = 1;            if (map[i - 1][j] == 1 && map[i][j + 1] == 1)                map[i][j] = 1;            if (map[i + 1][j] == 1 && map[i][j + 1] == 1)                map[i][j] = 1;        }    }    */    exit_i = 2 * h - 1;//终点坐标,将出口的前一个点设为终点,最少步数要加一    exit_j = 2 * w - 1;}int bfs() {       queue<P> que;    for (int i = 0; i < 65; i++) {        for (int j = 0; j < 65; j++) {            dist[i][j] = INF;//设为这样可以判断是否已经访问,走回头路是会无谓增长路途的        }    }    que.push(P(1, 1));//将起点放入队列    dist[1][1] = 0;//起点步数为0       while (que.size()) {//只要队列非空就还有格子要走完,就要走        P p = que.front();        que.pop();//将队头扔掉,相当于这里已经走过了        if (p.first == exit_i && p.second == exit_j)//走到了终点就结束            break;               for (int i = 0; i < 4; i++) {                       int toi = p.first + to_i[i];//接下来要走到的地方            int toj = p.second + to_j[i];                       if (1 <= toi && toi < 2 * h && 1 <= toj && toj < 2 * w //首先是不能越界                && map[(toi + p.first) / 2][(toj + p.second) / 2] == 0 //然后是中间的一步要没有墙,注意这里我们是一次走两格,但实际上两个实际格子之间有个墙壁,因此我们是每次走一格加一个墙壁(看上面的图)                && map[toi][toj] == 0 //而且走到的点也不能是墙壁                && dist[toi][toj] == INF) {//并且要走的点是没有去过的                                   que.push(P(toi, toj));//将走到的点加入队列                dist[toi][toj] = dist[p.first][p.second] + 1;//要走到的点的距离            }        }    }       return dist[exit_i][exit_j] + 1;//返回终点值}int main() {       int i, j, dis;       while (scanf("%d%d", &w, &h) && w && h) {               make_map(w, h);        /*        for (i = 0; i <= 2 * h; i++) {            for (j = 0; j <= 2 * w; j++) {                printf("%d", map[i][j]);            }            printf("\n");        }        */        dis = bfs();               if (dis == INF + 1)//表示没找到            printf("0\n");        else            printf("%d\n", dis);    }    return 0;}



0 0
原创粉丝点击