(新版)SJTU-OJ-1032. 泷的旅途

请添加图片描述

题目描述

深秋季节,天气渐凉,三叶由于最近期中考试太过忙碌,连续熬夜,不慎染上了感冒。泷听说后,非常担忧,于是决定出发去看三叶。已知泷和三叶处在一个矩形网格上,泷每次可以上下左右移动一格,但是他不能越过边界。要知道,泷虽然擅长体育,但是他的体力毕竟是有限的,已知泷的初始体力为6点,他每移动一格就要耗费一点体力,如果体力耗尽他就不能继续前进。幸运的是,三叶预想到了这一点,于是她提前请人帮忙在一些网格上放置了亲手做的便当。如果泷到达了放有便当的网格,那么他的体力值可以瞬间得到补充,恢复为6。值得注意的是,如果泷到达有便当的网格时体力已经为0,则他连吃饭的力气都没有了,就视为不可到达。如果他到达终点时体力为0,也视为不可到达。已知泷每走一格耗时为1,网格上的有些点上有不可逾越的建筑物,不能通过。

  • 数字 0:建筑物。(不允许通过)
  • 数字 1:空地,泷可以自由行走。
  • 数字 2:泷出发点, 也是一片空地。(行程起点)
  • 数字 3:三叶所在地。(行程终点)
  • 数字 4:便当所在地。

以标号为2的网格为起点,标号为3的网格为终点,问,泷能否见到三叶?如果能, 最短需要多长时间呢?

输入格式

第一行两个数字,网格的行数和列数,n,m。

第2至n+1行,描述整个网格。

输出格式

如果可到达,输出最短用时,否则输出-1。

样例输入

3 3
2 1 1
1 1 0
1 1 3

样例输出

4

数据范围

  • 对于 70 % 70\% 70%的数据 0 < n , m ≤ 20 0<n,m \le 20 0<n,m20;
  • 对于 30 % 30\% 30%的数据 0 < n , m ≤ 300 0<n,m \le 300 0<n,m300.

题目解答

      好难的一道题似乎(没错我卡了三天o(╥﹏╥)o)最后还是一位ACM的大佬指点下才做出来的
请添加图片描述请添加图片描述请添加图片描述请添加图片描述请添加图片描述请添加图片描述请添加图片描述请添加图片描述请添加图片描述请添加图片描述请添加图片描述请添加图片描述请添加图片描述请添加图片描述请添加图片描述请添加图片描述请添加图片描述请添加图片描述请添加图片描述请添加图片描述请添加图片描述请添加图片描述请添加图片描述请添加图片描述请添加图片描述请添加图片描述请添加图片描述请添加图片描述请添加图片描述请添加图片描述请添加图片描述请添加图片描述请添加图片描述请添加图片描述请添加图片描述请添加图片描述
      所以这个题目加入了能量值考虑,这就很麻烦了,我之前也考虑了很多递归的算法,但是结果不是超时就是答案错误。不妨列一下可能会有的问题:希望也可以帮助初学这个题目的玩家2333。

  • 问题一:到底是用BFS还是用DFS?
  • 解答:实践证明DFS只能通过 70 % 70\% 70% 的数据。 题目数据中有 70 % 70\% 70% 的数据地图规模是小于20格的,可以在规定时间内通过。但是一旦规模扩大了(达到300的边长的时候)就会超时!
  • 问题二:可否通过减分支的方法优化DFS ?
  • 解答:不可以,还是会超时!实践证明,当我们减去 超过 6 步以上仍然没有食物的路线,减去 在递归途中就超过已经找到可行方案的距离,规模扩大了(达到300的边长的时候)依然会超时
  • 问题三:可否结合递归与BFS一起查找?具体思路如下,利用BFS查找出发点周围 5 步以内的地图,(因为6步的时候一定人会没有吃的然后挂了)然后在以地图里面查找到的食物点作为起点,利用递归,在新的起点继续查找?
  • - 解答:不可以,首先,假设一个非常变态的情况,地图里面除了起点和终点全部是便当,那这个函数就会爆炸。其次,如果在查找的没有标记,这个函数就是一个死循环,起点 -> A便当 -> B便当 -> A便当 -> B便当 ……无穷无尽循环,更何况还有 C,D,E便当更多的循环。
  • 问题四:(接问题三)如果我标记了会怎么样?
  • 解答:首先,利用BFS查找出发点周围 5 步以内的地图,这个步骤相当于一个雷达,扫描周围的环境,扫描的结果是可能找到若干的便当,也可能啥都没找到。如果是后者那没事了搜索停止,如果是前者,我们要决定搜索方法,怎么搜索,这若干个便当,是全部作为起点,还是按照条件筛选出部分作为新的起点,然后再去查找。
  • 问题五:(接问题四)可否在最开始前以终点为中心,扫描周围环境,保存在一个数组里面,然后以起点为中心,步数为5扫描周围环境,比较所有的便当离终点的距离,选距离终点最近的便当到达,然后循环递归,直到终点?
  • 解答:不可以,实践证明,这种方法只能通过 70 % 70\% 70% 的数据。原因如下。假设下面这种图,空白的是空地,起点和终点是2,3,用黄色和橙色标出,蓝色的是食物,红色的是禁止去的区域。显然,唯一的方法是往上面绕远路,不能走下面的近路,但是按照问题里面所说的,以终点为雷达扫描周围距离,再以起点扫描周围步数5,会找到两个便当(这没错,一个在起点正北,另一个正南),然后判断这两个便当,显然是下面的便当距离终点近,递归进入第二层,以正南的便当作为起点,发现周围没有吃的了,就会报错认为无法到达。
    在这里插入图片描述
  • 问题六:如何解决这种问题?
  • 解答:建立三维数组,我们假设这一片区域是一个有6层楼房的区域。(说白了就是变成原来的每个二维区域里面又有了高度。)开始的时候我们在起点的六楼,然后我们往周围查找,每移动一个,下一层高度,一旦有吃的立马恢复到六楼,一旦人到了一楼而且没有吃的人就挂了。这个是整体的思路。
  • 问题七:如何记录走的步数?
  • 解答:首先我们要初始化这个三维数组空间的所有元素为 INT_MAX ,然后起点的六楼我们单独修改值为 0。开始查找,【比如在水平面往北可以走,那就往北走,还是用队列的知识,但是往北走的楼层数要降低为5楼(能量消耗一个)坐标、楼层都要记录下来,用 push 函数推入队伍中。】大括号内容重复,向北向南向东向西搜索,可以就入队,然后再队伍里每次读取一个继续搜索。
  • 问题八:如何避免重复搜索,重复吃便当?
  • 解答:首先,我们走的步数肯定是远远小于 INT_MAX = 21474836470 的值的。即使是最大的地图。与其单独开一个数组什么的记录已经搜索的,不如我们就用三维数组的数字来判断是否搜索过。如果值是 INT_MAX = 21474836470 ,肯定没搜索过。
  • 问题九:可否定义一个 二维的bool数组 来记录下已经搜索的水平位置,然后在每次搜索之前, 用二维bool数组决定是否搜索该坐标,避免重复搜索,重复吃便当?
  • 解答:不可以!这样会导致补充便当后,部分位置的数据没有更新!!!例如,浅蓝色是我们当前队伍里面队首,我们的搜索顺序是先南,然后东,然后北,最后西,(灰色)搜索完南部的那个位置后,我们搜索东部,发现有吃的,好呀,但是此时浅蓝色位置、浅蓝色南部的位置都被搜索了,做好标记,不会再搜索了,所以 从浅蓝色往东那个分支就自然而然的终结了,为什么?因为你用的是bool数组来决定是否搜索该坐标,往东的那个分支最多搜索向南一次,然后终结,程序失败。
          那 从浅蓝色往西的那个分支呢,也会终结,无法到达位置 3。为什么,因为没能量啦。所以这就说明,不能用二维bool数组决定是否搜索该坐标。
    在这里插入图片描述
  • 问题十:如何理解用三维数组的数字来判断是否搜索过?可以避免重复。
  • 解答:确实这是一个有一点抽象的问题,我们这样想。假设开始有一个毒气弹,放在起始的位置的六楼,然后这个毒气弹爆炸,开始向周围扩散,水平方向扩散一格,楼层数降低一,一旦毒气弹的气体扩散到了一楼,有没有遇上便当,那这个毒气自动失效,不再扩散。这就是这个问题的模型。此外,毒气每进入一个新的三维空间之前,都要判断之前有没有毒气已经进来过,进入新空间后,都要在里面写下花费的时间[或者说是距离]。
          那么我们描述某一处毒气的扩散情况需要什么参数呢?一个参数是扩散的时间(也就是从起点到该时刻毒气扩散的距离),另一个参数是当前的三维坐标。最初的时候三维坐标都被初始化 INT_MAX ,一旦被修改,一定就是之前已经有毒气到达,后来毒气在进入每一个三维空间前都要判断之前有没有进入过,如果之前进入过,那么现在这一段毒气进入完全没有必要,(为啥?之前已经有毒气进去了,之前的毒气花费的时间[或者说是距离]明显要少,所以没有必要再扩散进去,这就掉头看看周围)。
  • 问题十一:如何处理便当问题?
  • 我们知道,在使用BFS的时候要用到两个变量 nowplace,nextplace,后一个变量指示的位置基于前一个变量,也就是说后一个变量要遍历前一个变量北、东、南、西的、距离一个单位的位置,nowplace每次要读取队伍最前面的元素,然后把队伍最前面的元素弹出,所以处理便当问题有两个选择,一个选择是基于 nowplace,判断它【也是队queue最前面的元素】那里是不是有便当,另一个选择是基于 nextplace 判断。
          思考一下,你就会选择第二种。【理由】两个选择我们还是用毒气模型来解释,第一个选择就是,管他所在的位置有没有便当,先扔进队伍里面push进来,然后后面慢慢来处理,如果后来检测到有便当,我们就把位置升高到六楼,第二个选择就是,我在push进队伍里面之前,先看看有没有便当,有的话就直接扩散到六楼。显然第二个更好理解吧,不会调整位置升来升去的。就很头大,而且升高位置后改数据也很麻烦。【其实差别应该不大吧,效果是等效的应该,个人觉得】好处就是,选择第二种我们可以快速过滤数据,队伍里的东西,只要坐标是一楼,统统pass,为什么?之前已经通过食物有无检测了,还在一楼只能挂,没食物了,就算周围有食物,按照题目所说,体力为0 的时候不能吃东西。
  • 问题十二:搜索到终点后还会搜索吗?
  • 解答:是的,可能会。还是用毒气扩散模型,如果到了终点,并且是2楼以上,就会继续搜索周围的环境,继续扩散。但是,为了提高程序效率,你也可以就此终止,用一个 if 判断就可以实现终止,记得还有队列要清空哦~

       上AC代码!!! 如果还是不好理解,你不妨把之前的二维的广度优先搜索转换为三维的广度优先搜索,代码就很好理解了,值得注意的是,一旦到了一楼就要终止!因为没能量了。代码我还是加一下注释,方便阅读

#include <iostream>
#include <string.h>
#include <limits.h>
#include <queue>
using namespace std;

class node
{
    public:
        int x;
        int y;
        int height;						// 与之前不同的是,多了一个height 表示楼层
};

node departure, destination;
int m, n;
int testmap[310][310];
int stepmap[310][310][7];
int dx[4] = {0, 0, 1, -1};
int dy[4] = {1, -1, 0, 0};
int memsetmax;

void bfs(node departure)
{
    stepmap[departure.x][departure.y][6] = 0;		// 起点六楼初始化0
    queue<node> bfsque;
    node nowplace, nextplace;
    bfsque.push(departure);
    while(!bfsque.empty())
    {
        nowplace = bfsque.front();
        bfsque.pop();
        if(nowplace.height == 1)	// 到一楼了,直接pass
        {
            continue;
        }

        for (int i = 0; i < 4; i++)
        {
            nextplace.x = nowplace.x + dx[i];
            nextplace.y = nowplace.y + dy[i];
            nextplace.height = nowplace.height - 1;
            
            if (nextplace.x < 0 || nextplace.x >= n || nextplace.y < 0 || nextplace.y >= m || testmap[nextplace.x][nextplace.y] == 0)
            {
                continue;				// 数组下标不合法,直接pass
            }
            
            if(testmap[nextplace.x][nextplace.y] == 4 )	// 处理有便当的 nextplace 
            {
                if(stepmap[nextplace.x][nextplace.y][6] == memsetmax)
                {
                    nextplace.height = 6;				// 调整到六楼
                    stepmap[nextplace.x][nextplace.y][6] = stepmap[nowplace.x][nowplace.y][nowplace.height] + 1;
                    bfsque.push(nextplace);				// 入队!
                }
            }

            else if (stepmap[nextplace.x][nextplace.y][nextplace.height] == memsetmax)
            {
                stepmap[nextplace.x][nextplace.y][nextplace.height] = stepmap[nowplace.x][nowplace.y][nowplace.height] + 1;
                bfsque.push(nextplace);				// 同bfs常见操作
            }
        }
    }
}


int main()
{
    memset(stepmap, 127, sizeof(stepmap));		// 值得一提的是 这个操作不是把所有值设为127
    memsetmax = stepmap[0][0][0];				// 而是一个很大的值,接近 INT_MAX

    cin >> n >> m;
    for (int i = 0; i < n; i++)
    {
        for (int j = 0; j < m; j++)
        {
            cin >> testmap[i][j];
            switch (testmap[i][j])
            {
            case 2:
                departure.x = i;
                departure.y = j;
                departure.height = 6;
                break;
            case 3:
                destination.x = i;
                destination.y = j;
                break;
            default:
                break;
            }
        }
    }
    int result = memsetmax;
    bfs(departure);
    for (int i = 1; i <= 6; i++)
    {
        result = min(stepmap[destination.x][destination.y][i], result);
    }

    if (result == memsetmax)
        cout << "-1";
    else
        cout << result;
    system("pause");
    return 0;
}

小结 三维广度优先搜索

       三维广度优先搜索可以解决带有能量值的途径问题,本质是BFS搜索,模型是毒气扩散,按照楼层递减,实现途径是在class类定义的时候多定义一个变量即可,然后再后续的时候,考虑到楼层 height 的变化。其余的同之前的BFS搜索即可。若有问题,可以参考上面的样例问题,是我在写程序的时候遇到的,经历了三天的试错后总结的问题,新手也很可能有类似的问题,可以攻参考。 最后附上自己写错的代码,纪念一下下。

错误的尝试

尝试一 DFS

       【错误原因】超时,不适合大地图。

#include <iostream>
#include <limits.h>
#include <string.h>
using namespace std;

class node
{
    public:
        int x;
        int y;
};

node departure,destionation;
int n, m;
int testmap[310][310];
bool book[310][310];
bool IfFind = false;
int result = INT_MAX;
int dx[4] = {0, 0, 1, -1};
int dy[4] = {1, -1, 0, 0};

void dfs(int nx,int ny,int energy,int distance)
{
    if (energy <= 1 && testmap[nx][ny] != 4)
    {
        return;
    }

    if (distance >= result)
    {
        return;
    }

    if (nx == destionation.x && ny == destionation.y)
    {
        IfFind = true;
        if (distance < result)
        {
            result = distance;
        }
        return;
    }
    

    if (testmap[nx][ny] == 4)
    {
        energy = 6;
    }
    
    int ntx, nty;
    for (int i = 0; i < 4; i++)
    {
        ntx = nx + dx[i];
        nty = ny + dy[i];
        if (ntx >= n || ntx < 0 || nty >= m || nty < 0 || testmap[ntx][nty] == 0)
        {
            continue;
        }

        if (book[ntx][nty] == false)
        {
            book[ntx][nty] = true;
            dfs(ntx, nty, energy - 1, distance + 1);
            book[ntx][nty] = false;
        }
    }
}


int main()
{
    memset(book, false, sizeof(book));

    cin >> n >> m;
    for (int i = 0; i < n; i++)
    {
        for (int j = 0; j < m; j++)
        {
            cin >> testmap[i][j];
            switch (testmap[i][j])
            {
            case 2:
                departure.x = i;
                departure.y = j;
                break;
            case 3:
                destionation.x = i;
                destionation.y = j;
            default:
                break;
            }
        }
    }
    dfs(departure.x, departure.y, 6, 0);
    if (IfFind == false)
    {
        cout << "-1";
    }
    else
        cout << result;
    system("pause");
    return 0;
}
尝试二 BFS

       【错误原因】沉下心来想这是最接近成功的一次,几乎就啊哟呼之欲出了三维数组,错误原因在于用 bool 数组判断是否到过某些位置。具体分析见上文。

#include <iostream>
#include <string.h>
#include <queue>
using namespace std;

class node
{
    public:
        int x;
        int y;
        int energy;
};

node departure,destionation;
int n, m;
int testmap[310][310];
int step[310][310];
int dx[4] = {0, 0, 1, -1};
int dy[4] = {1, -1, 0, 0};
bool ifArrive[310][310];

bool bfs_CheckNextstep(node checkobject)
{
    if (checkobject.x < 0 || checkobject.x >= n)
        return false;
    if (checkobject.y < 0 || checkobject.y >= m)
        return false;
    if (testmap[checkobject.x][checkobject.y] == 0)
        return false;
    if (ifArrive[checkobject.x][checkobject.y] == true)
        return false;
    if (checkobject.energy == 0)
        return false;
    else 
        return true;
    // if (checkobject.x >= 0 && checkobject.x < n && checkobject.y >= 0 && checkobject.y < m && checkobject.energy > 0 && ifArrive[checkobject.x][checkobject.y] == false)
    //     return true;
    // else
    //     return false;
}

// 广度优先搜索,传入的时候传入一个节点node!
void bfs_Main(node departure)
{
    memset(step, 0, sizeof(step));
    memset(ifArrive, false, sizeof(ifArrive));
    // 首先定义一个队列!
    queue<node> bfsque;
    bfsque.push(departure);
    ifArrive[departure.x][departure.y] = true;
    node currentplace, nextplace;
    while (!bfsque.empty())
    {
        currentplace = bfsque.front();
        bfsque.pop(); // 把最前面的元素弹出去!

        if (testmap[currentplace.x][currentplace.y] == 4)
        {
            currentplace.energy = 6;
        }        
        
        for (int i = 0; i < 4; i++)
        {
            nextplace.x = currentplace.x + dx[i];
            nextplace.y = currentplace.y + dy[i];
            nextplace.energy = currentplace.energy - 1;
            if (bfs_CheckNextstep(nextplace) == true)
            {
                step[nextplace.x][nextplace.y] = step[currentplace.x][currentplace.y] + 1;
                ifArrive[nextplace.x][nextplace.y] = true;
                bfsque.push(nextplace);
            }
        }
    }
}

int main()
{
    cin >> n >> m;
    for (int i = 0; i < n; i++)
    {
        for (int j = 0; j < m; j++)
        {
            cin >> testmap[i][j];
            switch (testmap[i][j])
            {
            case 2:
                departure.x = i;
                departure.y = j;
                departure.energy = 6;
                ifArrive[departure.x][departure.y] = true;
                break;
            case 3:
                destionation.x = i;
                destionation.y = j;
            default:
                break;
            }
        }
    }

    bfs_Main(departure);
    cout << endl;
    for (int i = 0; i < n; i++)
    {
        for (int j = 0; j < m; j++)
        {
            cout << step[i][j] << "\t";
        }
        cout << endl;
    }
    if (ifArrive[destionation.x][destionation.y] == false)
        cout << "-1" << endl;
    else 
        cout << step[destionation.x][destionation.y];
    system("pause");
    return 0;
}
尝试三 BFS+递归

       【错误原因】没搞清楚递归的起点如何选择

#include <iostream>
#include <queue>
#include <string.h>
#include <limits.h>
using namespace std;

class node
{
    public:
        int x;
        int y;
};

class foodnode
{
    public:
        int x;
        int y;
};

foodnode foodplace[100000];
node departure, destionation;
int m, n;
int testmap[310][310];
int dx[4] = {0, 0, 1, -1};
int dy[4] = {1, -1, 0, 0};
int foodnum = 0;

// 只找六步以内!
void find_Surrounding(node departure)
{
    bool ifChecked[310][310];
    int step[310][310];
    memset(ifChecked, false, sizeof(ifChecked));
    memset(step, 0, sizeof(step));
    queue<node> bfsque;
    ifChecked[departure.x][departure.y] = true;
    node nowplace, nextplace;
    bfsque.push(departure);
    while (!bfsque.empty())
    {
        nowplace = bfsque.front();
        bfsque.pop(); // 把最前面的元素弹出去!

        for (int i = 0; i < 4; i++)
        {
            nextplace.x = nowplace.x + dx[i];
            nextplace.y = nowplace.y + dy[i];
        
            if (nextplace.x >= n || nextplace.x < 0 || nextplace.y >= m || nextplace.y < 0 || testmap[nextplace.x][nextplace.y] == 0)
            {
                continue;
            }

            if (ifChecked[nextplace.x][nextplace.y] == false && step[nowplace.x][nowplace.y] < 5)
            {
                step[nextplace.x][nextplace.y] = step[nowplace.x][nowplace.y] + 1;
                // cout << "nextplace.x:  " << nextplace.x << endl;
                // cout << "nextplace.y:  " << nextplace.y << endl;
                // cout << "step[nextplace.x][nextplace.y]:  " << step[nextplace.x][nextplace.y] << endl;
                ifChecked[nextplace.x][nextplace.y] = true;
                bfsque.push(nextplace);
            }
        }
    }

    // for (int i = 0; i < m; i++)
    // {
    //     for (int j = 0; j < n; j++)
    //     {
    //         cout << step[i][j] << "\t";
    //     }
    //     cout << endl;
    // }
}


int main()
{
    cin >> n >> m;
    for (int i = 0; i < n; i++)
    {
        for (int j = 0; j < m; j++)
        {
            cin >> testmap[i][j];
            switch (testmap[i][j])
            {
            case 2:
                departure.x = i;
                departure.y = j;
                break;
            case 3:
                destionation.x = i;
                destionation.y = j;
                break;
            case 4:
                foodplace[foodnum].x = i;
                foodplace[foodnum].y = j;
                foodnum++;
                break;
            default:
                break;
            }
        }
    }
    find_Surrounding(departure);

    system("pause");
    return 0;
}

尝试四 BFS+递归

       【错误原因】同上

#include <iostream>
#include <cstring>
#include <queue>
#include <limits.h>
using namespace std;

class node 
{
    public:
        int x;
        int y;
};

class foodnode
{
    public:
        int x;
        int y;
        int step;
};

node departure, destination;
int testmap[310][310];
int step_for_findSurronding[310][310];
int step_for_destination[310][310];
bool book_for_departure_surrending[310][310];
bool foodmap[310][310];
int dx[4] = {0, 0, 1, -1};
int dy[4] = {1, -1, 0, 0};
int m, n;
int result = INT_MAX;
bool If_Meet = false;

bool common_check(node object)
{
    if (object.x < 0 || object.x >= n)
        return false;
    if (object.y < 0 || object.y >= m)
        return false;
    if (testmap[object.x][object.y] == 0)
        return false;
    else 
        return true;
}





void destination_surronding(node destination)
{
    bool book_for_destination_surronding[310][310];
    memset(book_for_destination_surronding, false, sizeof(book_for_destination_surronding));
    memset(step_for_destination, 0, sizeof(step_for_destination));
    queue<node> bfsque;
    node nowplace, nextplace;
    bfsque.push(destination);
    book_for_destination_surronding[destination.x][destination.y] = true;
    while(!bfsque.empty())
    {
        nowplace = bfsque.front();
        bfsque.pop();

        for (int i = 0; i < 4; i++)
        {
            nextplace.x = nowplace.x + dx[i];
            nextplace.y = nowplace.y + dy[i];
            if (common_check(nextplace) == true && book_for_destination_surronding[nextplace.x][nextplace.y] == false)
            {
                step_for_destination[nextplace.x][nextplace.y] = step_for_destination[nowplace.x][nowplace.y] + 1;
                book_for_destination_surronding[nextplace.x][nextplace.y] = true;
                bfsque.push(nextplace);
            }
        }

    }

} 

void print_departure_surronding()
{
    for (int i = 0; i < m; i++)
    {
        for (int j = 0; j < n; j++)
        {
            cout << step_for_findSurronding[i][j] << "\t";
        }
        cout << endl;
    }
}


// 下面这个函数涉及到递归

void departure_surrending(node departure, int distance)
{
    memset(book_for_departure_surrending, false, sizeof(book_for_departure_surrending));
    memset(step_for_findSurronding,0,sizeof(step_for_findSurronding));
    queue<node> bfsque1;
    queue<foodnode> foodtemp;
    node nowplace, nextplace;
    foodnode temp;  // 用于转换,以便于推入食物的队伍
    bfsque1.push(departure);
    book_for_departure_surrending[departure.x][departure.y] = true;
    while(!bfsque1.empty())
    {
        nowplace = bfsque1.front();
        bfsque1.pop();
        
        if(nowplace.x == destination.x && nowplace.y == destination.y)
        {
            // 检测到终点
            If_Meet = true;
            distance = distance + step_for_findSurronding[nowplace.x][nowplace.y];
            if (distance < result)
            {
                result = distance;
            }
            while(!bfsque1.empty())     bfsque1.pop();    
            return;
        }

        if (testmap[nowplace.x][nowplace.y] == 4 && foodmap[nowplace.x][nowplace.y] == false)
        {
            temp.x = nowplace.x;
            temp.y = nowplace.y;
            temp.step = step_for_findSurronding[nowplace.x][nowplace.y];
            foodtemp.push(temp);
        }

        for (int i = 0; i < 4; i++)
        {
            nextplace.x = nowplace.x + dx[i];
            nextplace.y = nowplace.y + dy[i];
            if (common_check(nextplace) == true && book_for_departure_surrending[nextplace.x][nextplace.y] == false && step_for_findSurronding[nowplace.x][nowplace.y] <= 4)
            {
                step_for_findSurronding[nextplace.x][nextplace.y] = step_for_findSurronding[nowplace.x][nowplace.y] + 1;
                book_for_departure_surrending[nextplace.x][nextplace.y] = true;
                bfsque1.push(nextplace);
            }
        }
    }
    cout << "!--------------------------!" << endl;
    print_departure_surronding();
    if(!foodtemp.empty())
    {
        int steptemp;
        foodnode first, last;
        last = foodtemp.back();
        first = foodtemp.front();
        // 下面开始递归!
        // cout << foodtemp.size() << endl;
        while ((first.step) < (last.step))
        {
            foodtemp.pop();
            first = foodtemp.front();
        }
        while (!foodtemp.empty())
        {
            departure.x = foodtemp.front().x;
            departure.y = foodtemp.front().y;
            steptemp = foodtemp.front().step;
            cout << "departure.x: " << departure.x << "   departure.y:   " << departure.y << endl;
            foodtemp.pop();
            foodmap[departure.x][departure.y] = true;
            departure_surrending(departure, distance + steptemp);

        }
    }

}


int main()
{
    memset(foodmap, false, sizeof(foodmap));
    cin >> n >> m;
    for (int i = 0; i < n; i++)
    {
        for (int j = 0; j < m; j++)
        {
            cin >> testmap[i][j];
            switch (testmap[i][j])
            {
            case 2:
                departure.x = i;
                departure.y = j;
                break;
            case 3:
                destination.x = i;
                destination.y = j;
            default:
                break;
            }
        }
    }

    destination_surronding(destination);
    departure_surrending(departure, 0);
    if (If_Meet == true)
        cout << result;
    else
        cout << "-1";
    // print_destination_surronding();
    system("pause");
    return 0;
}
尝试五 BFS+递归

       【错误原因】同上

#include <iostream>
#include <cstring>
#include <queue>
#include <limits.h>
using namespace std;

class node 
{
    public:
        int x;
        int y;
};

class foodnode
{
    public:
        int x;
        int y;
        int step;
        long int walkstep;
};

node departure, destination;
int testmap[310][310];
int step_for_findSurronding[310][310];
int step_for_destination[310][310];
bool book_for_departure_surrending[310][310];
bool foodmap[310][310];
int dx[4] = {0, 0, 1, -1};
int dy[4] = {1, -1, 0, 0};
int m, n;
long int result = 10000000;
bool If_Meet = false;

bool common_check(node object)
{
    if (object.x < 0 || object.x >= n)
        return false;
    if (object.y < 0 || object.y >= m)
        return false;
    if (testmap[object.x][object.y] == 0)
        return false;
    else 
        return true;
}

void destination_surronding(node destination)
{
    bool book_for_destination_surronding[310][310];
    memset(book_for_destination_surronding, false, sizeof(book_for_destination_surronding));
    memset(step_for_destination, 0, sizeof(step_for_destination));
    queue<node> bfsque;
    node nowplace, nextplace;
    bfsque.push(destination);
    book_for_destination_surronding[destination.x][destination.y] = true;
    while(!bfsque.empty())
    {
        nowplace = bfsque.front();
        bfsque.pop();

        for (int i = 0; i < 4; i++)
        {
            nextplace.x = nowplace.x + dx[i];
            nextplace.y = nowplace.y + dy[i];
            if (common_check(nextplace) == true && book_for_destination_surronding[nextplace.x][nextplace.y] == false)
            {
                step_for_destination[nextplace.x][nextplace.y] = step_for_destination[nowplace.x][nowplace.y] + 1;
                book_for_destination_surronding[nextplace.x][nextplace.y] = true;
                bfsque.push(nextplace);
            }
        }

    }

} 

void print_destination_surronding()
{
    for (int i = 0; i < n; i++)
    {
        for (int j = 0; j < m; j++)
        {
            cout << step_for_destination[i][j] << "\t";
        }
        cout << endl;
    }
}

void print_departure_surronding()
{
    for (int i = 0; i < n; i++)
    {
        for (int j = 0; j < m; j++)
        {
            cout << step_for_findSurronding[i][j] << "\t";
        }
        cout << endl;
    }
}

// 下面这个函数涉及到递归

void departure_surrending(node departure, long int distance)
{
    memset(book_for_departure_surrending, false, sizeof(book_for_departure_surrending));
    memset(step_for_findSurronding,0,sizeof(step_for_findSurronding));
    queue<node> bfsque1;
    foodnode foodplace[50];
    int foodnum = 0;
    node nowplace, nextplace;
    
    bfsque1.push(departure);
    book_for_departure_surrending[departure.x][departure.y] = true;
    while(!bfsque1.empty())
    {
        nowplace = bfsque1.front();
        bfsque1.pop();
        
        if(nowplace.x == destination.x && nowplace.y == destination.y)
        {
            // 检测到终点
            If_Meet = true;
            distance = distance + step_for_findSurronding[nowplace.x][nowplace.y];
            cout << "possible : " << distance << endl;
            if (distance < result)
            {
                result = distance;
            }
            while(!bfsque1.empty())
            {
                bfsque1.pop();    
            }     
            return;
        }

        if (testmap[nowplace.x][nowplace.y] == 4 && foodmap[nowplace.x][nowplace.y] == false)
        {
            foodplace[foodnum].x = nowplace.x;
            foodplace[foodnum].y = nowplace.y;
            foodplace[foodnum].step = step_for_destination[nowplace.x][nowplace.y];
            foodplace[foodnum].walkstep = step_for_findSurronding[nowplace.x][nowplace.y];
            foodnum++;
        }

        for (int i = 0; i < 4; i++)
        {
            nextplace.x = nowplace.x + dx[i];
            nextplace.y = nowplace.y + dy[i];
            if (common_check(nextplace) == true && book_for_departure_surrending[nextplace.x][nextplace.y] == false && step_for_findSurronding[nowplace.x][nowplace.y] <= 4)
            {
                step_for_findSurronding[nextplace.x][nextplace.y] = step_for_findSurronding[nowplace.x][nowplace.y] + 1;
                book_for_departure_surrending[nextplace.x][nextplace.y] = true;
                bfsque1.push(nextplace);
            }
        }
    }
    
    print_departure_surronding();
    cout << "!! foodnum  " << foodnum << endl;
    int mindistance = foodplace[0].step;
    for (int i = 0; i < foodnum; i++)
    {
        cout << "possible step : " << (foodplace[i].step) << endl;
        if ((foodplace[i].step) < mindistance)
        {
            mindistance = foodplace[i].step;
        }
    }

    for (int j = 0; j < foodnum; j++)
    {
        if((foodplace[j].step) == mindistance)
        {
            departure.x = foodplace[j].x;
            departure.y = foodplace[j].y;
            cout << "departure.x: " << departure.x << "   departure.y:   " << departure.y << endl;
            foodmap[departure.x][departure.y] = true;
            departure_surrending(departure, distance + foodplace[j].walkstep);
        }
    }
}


int main()
{
    memset(foodmap, false, sizeof(foodmap));
    cin >> n >> m;
    for (int i = 0; i < n; i++)
    {
        for (int j = 0; j < m; j++)
        {
            cin >> testmap[i][j];
            switch (testmap[i][j])
            {
            case 2:
                departure.x = i;
                departure.y = j;
                break;
            case 3:
                destination.x = i;
                destination.y = j;
            default:
                break;
            }
        }
    }

    destination_surronding(destination);
    cout << "打印终点附近坐标" << endl;
    print_destination_surronding();
    cout << "打印终点附近坐标结束" << endl;
    departure_surrending(departure, 0);

    if (If_Meet == true)
        cout << result;
    else
        cout << "-1";
    system("pause");
    return 0;
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值