“Rescue(营救),ZOJ1649”的一种解法和疑惑

1.1题目编号:ZOJ1649

详见:http://acm.zju.edu.cn/onlinejudge/showProblem.do?problemCode=1649

1.2题目描述:

Angel 被MOLIGPY 抓住了,她被关在监狱里。监狱可以用一个N×M 的矩阵来描述,1

Angel 的朋友想去营救Angel。他的任务是接近Angel。约定“接近Angel”的意思是到达Angel被关的位置。如果Angel 的朋友想到达某个方格,但方格中有警卫,那么必须杀死警卫,才能到达这个方格。假定Angel 的朋友向上、下、左、右移动一步用时为1 个单位时间,杀死警卫用时也为1 个单位时间。假定Angel 的朋友是如此强壮,可以杀死所有的警卫。你的任务是计算Angel 的朋友接近Angel 至少需要多长时间,只能向上、下、左、右移动,而且墙壁不能通过。

1.3输入描述

输入文件中包含多个测试数据。每个测试数据的第1 行为两个整数N和M,接下来有N行,每行有M个字符:"."代表道路,"a"代表Angel,"r"代表Angel的朋友,"#"代表墙壁,"x"代表警卫(注意,每个测试数据中字符"a"和"r"均只有一个)。输入数据一直到文件尾。

1.4输出描述

对输入文件中的每个测试数据,输出一个整数,表示接近Angel 所需的最少时间。如果无法接近Angel,则输出"PoorANGEL has to stay in the prison all his life."。

 “Rescue(营救),ZOJ1649”的一种解法和疑惑_第1张图片

 二、思路

题目的要求是,从r处出发,找到一条到达a处所需时间最短的路径,输出最短时间。

0.因为可能存在多条路径(而且考虑警卫造成的影响,步数最少的路径不一定是时间最短的路径),所以首先想到的是采用广度优先算法。使用一个二维数组记录到达该点的最少时间,这样就可以找到救出Angel的最少时间。

1.对于警卫,可以简单地处理为到达该点耗时比普通点多1

2.本题可以用比较典型的广度优先算法BFS来实现——建立一个Queue,依次把下一点出列,并把新的符合要求的点入列。Queue可以直接使用了C++提供的类型,但把什么东西入列使我们要确定的。这里我们构建一个Node结构体,包含三个元素:x,y,time,前二者指示坐标,后者指示到达该点所需的时间。

3.所以总体思路就是,从r点出发,向四个方向搜索,如果到达该点的时间,比原来记录的到达该点的时间更短,则从此点开始继续新的搜索(也即将该点入列)。当队列中的点被全部搜索后,若a点对应最小时间合理(不是初始设置的最大值),则能救出Angel。

  

值得一提的是:本题存在一个巨大的坑

虽然题目提到:“监狱可以用一个N×M 的矩阵来描述,1”,但ZOJ在测试用例中应该是用到了200以上的数据,所以若MAX设为200,则在ZOJ上测试时,报“Wrong Answer”,必须改成202才OK

看来以后做ZOJ上的题也都应该放宽一下数组边界。   

三、解答

完整程序如下,可以通过ZOJ的测试

/*
Rescue(营救),ZOJ1649
2016.05.26 Thu rainy by Pospro
详见博客 http://blog.csdn.net/pospro
*/
#include 
#include 
#include 
#define MAX 202
//注意,此处有巨坑!!虽然题目提到:1 Q;

int BFS()
{
    int i;
    int nextx, nexty, nexttime;

    while(!Q.empty())
    {
        fnode=Q.front(); //获得队列中第一个元素的位置,但只获得不删除,所以还要后面的pop,去除首元素
        Q.pop();

        for(i=0;i<8;i=i+2) //按照上右下左的顺序搜索四个方向是否可行
        {
            nextx=fnode.x+fx[i];    //下一个搜索点的x坐标
            nexty=fnode.y+fx[i+1];  //下一个搜索点的y坐标

            if(nextx<0||nextx>=N||nexty<0||nexty>=M||prison[nextx][nexty]=='#')
                continue; //如遇以上任何一种情况,换另一个方向试试;

            if(prison[nextx][nexty]=='x')
                nexttime=fnode.time+2; //遇到警卫需要多花一点时间
            else
                nexttime=fnode.time+1;

            //只有在按此路径进入下一位置所花的时间比以前少的情况下,继续朝此方向搜索才有意义
            if(nexttime

四、疑惑

虽然此题已解出,但还存有不少疑惑,望高手告知

1.采用深度优先算法是否可以解出此题?理由是?

2.我曾试图用INT_MAX(#include )来替代LGMN(#define LGNM 1000000),但一旦替代,就无法获得正确结果,这是什么原因?

3.关于BFS最后一个if语句的问题

版本1:

if(mintime[ex][ey]
版本2

if(mintime[ex][ey]==LGNM)
        return -1;
    else
        return mintime[ex][ey];
版本1是可用的,但一旦换成版本2,就无法得到正确结果。我知道完全等价的形式应该在版本2的if中使用>=,但是我觉得不会出现大于LGNM的情况啊,为什么>=换成==就会出错呢?

望高手在留言中给予解答,先谢过!


你可能感兴趣的:(算法,编程实例)