poj2049 Finding Nemo

Finding Nemo
Time Limit: 2000MS   Memory Limit: 30000K
Total Submissions: 8804   Accepted: 2069

Description

Nemo is a naughty boy. One day he went into the deep sea all by himself. Unfortunately, he became lost and couldn't find his way home. Therefore, he sent a signal to his father, Marlin, to ask for help. 
After checking the map, Marlin found that the sea is like a labyrinth with walls and doors. All the walls are parallel to the X-axis or to the Y-axis. The thickness of the walls are assumed to be zero. 
All the doors are opened on the walls and have a length of 1. Marlin cannot go through a wall unless there is a door on the wall. Because going through a door is dangerous (there may be some virulent medusas near the doors), Marlin wants to go through as few doors as he could to find Nemo. 
Figure-1 shows an example of the labyrinth and the path Marlin went through to find Nemo. 
poj2049 Finding Nemo_第1张图片

We assume Marlin's initial position is at (0, 0). Given the position of Nemo and the configuration of walls and doors, please write a program to calculate the minimum number of doors Marlin has to go through in order to reach Nemo.

Input

The input consists of several test cases. Each test case is started by two non-negative integers M and N. M represents the number of walls in the labyrinth and N represents the number of doors. 
Then follow M lines, each containing four integers that describe a wall in the following format: 
x y d t 
(x, y) indicates the lower-left point of the wall, d is the direction of the wall -- 0 means it's parallel to the X-axis and 1 means that it's parallel to the Y-axis, and t gives the length of the wall. 
The coordinates of two ends of any wall will be in the range of [1,199]. 
Then there are N lines that give the description of the doors: 
x y d 
x, y, d have the same meaning as the walls. As the doors have fixed length of 1, t is omitted. 
The last line of each case contains two positive float numbers: 
f1 f2 
(f1, f2) gives the position of Nemo. And it will not lie within any wall or door. 
A test case of M = -1 and N = -1 indicates the end of input, and should not be processed.

Output

For each test case, in a separate line, please output the minimum number of doors Marlin has to go through in order to rescue his son. If he can't reach Nemo, output -1.

Sample Input

8 9
1 1 1 3
2 1 1 3
3 1 1 3
4 1 1 3
1 1 0 3
1 2 0 3
1 3 0 3
1 4 0 3
2 1 1
2 2 1
2 3 1
3 1 1
3 2 1
3 3 1
1 2 0
3 3 0
4 3 1
1.5 1.5
4 0
1 1 0 1
1 1 1 1
2 1 1 1
1 2 0 1
1.5 1.7
-1 -1

Sample Output

5
-1

第一次碰到网格的题,搜了一下方法,最后总结出一个比较简单好理解的算法。

主要问题就是怎么把网格转化成二维图。

在这里我们把每个网格的左下角的点作为网格的坐标,用两个数组h和l来分别记录这个网格的下边和左边的权值,我们把墙的权值设为inf,门的权值为1,初始化为0,这样我们在读入数据的时后就把图建好。

搜索:利用广度优先搜索,这里有个坑点就是这货有可能根本就没在迷宫里面,这时候肯定穿过的门是0了。

在这里我们要好好考虑一下,首先就是状态,对于每一个网格我们可以走4个方向,首先就是墙我们是不能撞的,在这里,我们可以增加一个记录每一个点的权值和的数组,

初始化为inf。这样,我们只走能使得走入的下一个点的和变得更少的点,也就是满足dis[新点]>dis[旧点]+串xx的权值,我们才把这个新点入队。

并且这样还可以确保走过的点不会再走回去。

这时候我们就要避免一个问题,我们不可能一直在迷宫外面一直搜索下去,所以我们要设置一个边界,这个边界就是迷宫的大小(外面一层的点的坐标的最大值),注意这个地方不是网格的点的坐标的最大值,因为如果这样的话你看看示例就知道了,所以,我们要在迷宫外面多设一层网格,也就是迷宫外面一层的点的坐标的最大值。

同时我们还要考虑一个问题,那就是这不同与点的bfs,不同于往常,原因就是在一个网格里,它除了墙和门之外还有可能是什么都没有的!!

这样的话我们上下左右4个方向走完,压进队列的值,此时的状态并不一定是相同的,如果按照普通的搜索,每走一步步数必定加一,但这个就不同了,虽然我们不会去撞墙(因为墙的权值为inf,再加上自己(大于等于0))必定不会比新点(初始化为inf)小,但是因为并不是只有门的存在,所以,我们走一步之后可能步数并没有加一。

举个例子来说就是:poj2049 Finding Nemo_第2张图片

我用红色代表什么也没有,灰色代表门,那么先进入队列的是上面2号格子此时步数是要加一的,而后进队列的就是1号个子但是它此时的步数不需要加1,所以说如果照普通的搜索你搜索出来的就不一定是步数也就是穿过的门数最少的了。

我们的解决方法就是我们这次不用普通的队列而是优先队列,权值越小优先级越高,这样就解决了这个问题。

贴上代码:

#include 
#include 
#include 
#include 
#include 
using namespace std;
const int inf=0x3f3f3f;
const int N=250;


struct node
{
    int x,y,door;
    //步数少的优先
    bool operator<(const node &a)const
    {
        return a.doorq;
    for(i=0;i<=maxx;++i)
        for(j=0;j<=maxy;++j)dis[i][j]=inf;//初始化
    node k;
    k.x=0;k.y=0;k.door=0;//从他爸的地方为起始点
    dis[0][0]=0;
    q.push(k);
    while(!q.empty())
    {
        k=q.top();
        q.pop();
        if(k.x==sx&&k.y==sy)return ;//找到了就返回
        int x=k.x,   y=k.y;
        //向上走
        if(y+1<=maxy&&dis[x][y+1]>dis[x][y]+h[x][y+1])
        {
            dis[x][y+1]=dis[x][y]+h[x][y+1];//上面那面xx就是上个格子的下面xx
            k.x=x;
            k.y=y+1;
            k.door=dis[x][y+1];
            q.push(k);
        }
        //向下走
        if(y-1>=0&&dis[x][y-1]>dis[x][y]+h[x][y])
        {
            dis[x][y-1]=dis[x][y]+h[x][y];
            k.x=x;
            k.y=y-1;
            k.door=dis[x][y-1];
            q.push(k);
        }
        //向右走
        if(x+1<=maxx&&dis[x+1][y]>dis[x][y]+l[x+1][y])
        {
            dis[x+1][y]=dis[x][y]+l[x+1][y];
            k.x=x+1;
            k.y=y;
            k.door=dis[x+1][y];
            q.push(k);
        }
        //向左走
        if(x-1>=0&&dis[x-1][y]>dis[x][y]+l[x][y])
        {
            dis[x-1][y]=dis[x][y]+l[x][y];
            k.x=x-1;
            k.y=y;
            k.door=dis[x-1][y];
            q.push(k);
        }
    }
    dis[sx][sy]=-1;
}
int main()
{
    int x,y,d,t;
    int i;
    while(~scanf("%d%d",&n,&m))
    {
        if(n==-1&&m==-1)break;
        //你要知道并不是迷宫里面除了墙就是门的,可以什么都没有的,直接就穿过去了
        memset(h,0,sizeof(h));
        memset(l,0,sizeof(l));
        maxy=-1;maxx=-1;
        while(n--)
        {
            scanf("%d%d%d%d",&x,&y,&d,&t);
            if(d)
            {
                for(i=0;i=maxx||f2>=maxy)
        {
            printf("0\n");
            continue;
        }
        sx=f1;
        sy=f2;
        bfs();
        printf("%d\n",dis[sx][sy]);
    }
    return 0;
}



你可能感兴趣的:(广度优先搜索)