题目 1923: 蓝桥杯算法提高VIP-学霸的迷宫

题目

学霸抢走了大家的作业,班长为了帮同学们找回作业,决定去找学霸决斗。但学霸为了不要别人打扰,住在一个城堡里,城堡外面是一个二维的格子迷宫,要进城堡必须得先通过迷宫。因为班长还有妹子要陪,磨刀不误砍柴功,他为了节约时间,从线人那里搞到了迷宫的地图,准备提前计算最短的路线。可是他现在正向妹子解释这件事情,于是就委托你帮他找一条最短的路线。

输入
第一行两个整数n, m,为迷宫的长宽。
接下来n行,每行m个数,数之间没有间隔,为0或1中的一个。0表示这个格子可以通过,1表示不可以。假设你现在已经在迷宫坐标(1,1)的地方,即左上角,迷宫的出口在(n,m)。每次移动时只能向上下左右4个方向移动到另外一个可以通过的格子里,每次移动算一步。数据保证(1,1),(n,m)可以通过。

输出
第一行一个数为需要的最少步数K。
第二行K个字符,每个字符∈{U,D,L,R},分别表示上下左右。如果有多条长度相同的最短路径,选择在此表示方法下字典序最小的一个。

样例输入

3 3
001
100
110

样例输出

4
RDRD

数据规模和约定

有20%的数据满足:1<=n,m<=10
有50%的数据满足:1<=n,m<=50
有100%的数据满足:1<=n,m<=500

解题思路

本题需要找到最短路径,且如果有相同长度路径,按照字母序排列。如果采用深度优先搜索(DFS),我们需要搜索所有可能路径,选择其中符合要求的一条;但如果采用广度优先搜索(BFS),只每一步都按照字母序(‘D’,‘L’,‘R’,‘U’)去走,找到第一条到达终点的路径即可。显然,后者效率更优,因此,采用BFS解题。

首先,本题在BFS中的每一步都需要记录步数、当前坐标以及路径(一个字符串),因此,采用结构体队列。接下来BFS仍然使用常规思路:首先初始化第一步存入队列,之后每一次取队列最前面的结点,走下一步,并将走过的结点从可以走的路径上“抹去”(设置为1),若到达终点,输出并停止BFS;反之,存入队列并依此循环。

易错点

  1. 读入时注意换行符,对每一个数字进行读入时用scanf(“%c”,&temp)或者getchar;
  2. 要避免走回头路;
  3. 本题要使用BFS而不是DFS,因为只需要广泛寻找,找到先到达终点的路即可停止继续搜索。

代码

#include<bits/stdc++.h>
using namespace std;

int F = 0;//表示是否找到第一个到终点的最短路径
int r,column;//行,列
char a[501][501];//邻接矩阵
char D[4] = {'D','L','R','U'};//下左右上的字母序
int dir[4][2] = {{1,0},{0,-1},{0,1},{-1,0}};//对应的坐标移动

struct node{
    int x;
    int y;
    int steps;
    string con;
};

queue <struct node> q;

void BFS(){
    int i,tx,ty,nowx,nowy,lenc,step;
    struct node N,temp;
    string d;
    for (i=0;i<4;i++)//第一步的初始化
    {
        tx = 1+dir[i][0];
        ty = 1+dir[i][1];
        if (tx>=1 && ty>=1 && ty<=column && tx<=r && a[tx][ty]==0)//能走
        {
            N.con = D[i];
            N.x = tx;
            N.y = ty;
            N.steps = 1;
            q.push(N);
            a[tx][ty] = 1;
        }
    }
    
    while (!q.empty()){
        N = q.front();
        nowx = N.x;
        nowy = N.y;
        q.pop();
        for (i=0;i<4;i++)//四个方向
        {
            d = N.con;
            tx = nowx+dir[i][0];
            ty = nowy+dir[i][1];
            if (tx>0 && tx<=r && ty>0 && ty<=column && a[tx][ty]==0)//能走
            {
                a[tx][ty] = 1;
                d+=D[i];//加上新路径
                if (tx==r && ty==column)//第一个到终点的
                {
                    printf("%d\n",N.steps+1);
                    cout << d;
                    F = 1;
                    break;
                }
                else
                {
                    temp.x = tx;
                    temp.y = ty;
                    temp.con = d;
                    temp.steps = N.steps+1;
                    q.push(temp);
                }
            }
        }
        if (F==1)
            break;
    }
}

int main()
{
    int i,j;
    char temp;
    scanf("%d %d\n",&r,&column);//读入行列数
    for (i=1;i<=r;i++)
    {
        for (j=1;j<=column;j++)
        {
            scanf("%c",&temp);
            a[i][j] = temp-48;
        }
        getchar();//读入换行符
    }
    a[1][1] = 1;
    BFS();
    return 0;
}

错误代码

采用DFS,运行后时间超限(42分):

#include<bits/stdc++.h>
using namespace std;
int adj[501][501];
int r,c,Min=1000000;
int k = 0;//记录struct元素的数目
int dir[4][2] = {{1,0},{0,-1},{0,1},{-1,0}};//D,L,R,U
char D[4] = {'D','L','R','U'};//按照字母顺序排列
vector <char> q; 
char roads[500];
int len_r=0;

void DFS(int x, int y){
    int i,tx,ty,t;
    if (x==r && y==c)//到达出口
    {
        t = q.size();
        if (t<Min)//相等长度的将不再被替换,保证了按照字母顺序
        {
            Min = t;
            for (len_r=0;len_r<Min;len_r++)
                roads[len_r] = q[len_r];
            roads[len_r] = '\0';
        }
        return ;
    }
    for (i=0;i<4;i++)//四个方向
    {
        tx = x+dir[i][0];
        ty = y+dir[i][1];
        if (tx>0 && tx<=r && ty>0 && ty<=c && adj[tx][ty]==0)//能走
        {
            adj[tx][ty] = 1;
            q.push_back(D[i]);
            if (Min>q.size())//如果当前已经比min长了,不必再DFS
                DFS(tx,ty);
            q.pop_back();//回溯
            adj[tx][ty] = 0;
        }
    }
}

int main()
{
	int i,j;
	char temp;
	scanf("%d %d\n",&r,&c);
	for (i=1;i<=r;i++)
	{
	    for (j=1;j<=c;j++)
	    {
	        scanf("%c",&temp);
	        adj[i][j] = temp-48;
	    }
	    getchar();//换行符
	}
	adj[1][1] = 1;
	DFS(1,1);
	printf("%d\n%s",len_r,roads);
	return 0;
}

采用BFS+map,运行时间仍然超限(33分):

#include<bits/stdc++.h>
using namespace std;

int F = 0;//表示是否找到第一个到终点的最短路径
int r,column;//行,列
char a[501][501];//邻接矩阵
char D[4] = {'D','L','R','U'};//下左右上的字母序
int dir[4][2] = {{1,0},{0,-1},{0,1},{-1,0}};//对应的坐标移动

struct node{
    int x;
    int y;
    int steps;
};

queue <string> q;
map <string,struct node> N;

void BFS(){
    int i,tx,ty,nowx,nowy,lenc;
    string c,d;
    for (i=0;i<4;i++)//第一步的初始化
    {
        tx = 1+dir[i][0];
        ty = 1+dir[i][1];
        if (tx>=1 && ty>=1 && ty<=column && tx<=r && a[tx][ty]==0)//能走
        {
            c = D[i];
            q.push(c);
            N[c].x = tx;
            N[c].y = ty;
            N[c].steps = 1;
        }
    }
    
    while (!q.empty()){
        c = q.front();
        nowx = N[c].x;
        nowy = N[c].y;
        q.pop();
        for (i=0;i<4;i++)//四个方向
        {
            d = c;
            lenc = c.size();
            tx = nowx+dir[i][0];
            ty = nowy+dir[i][1];
            if (tx>0 && tx<=r && ty>0 && ty<=column && a[tx][ty]==0)//能走
            {
                d+=D[i];//加上新路径
                if (tx==r && ty==column)//第一个到终点的
                {
                    printf("%d\n",N[c].steps+1);
                    cout << d;
                    F = 1;
                    break;
                }
                else if (N[d].x==0)//未出现过
                {
                    q.push(d);
                    N[d].x = tx;
                    N[d].y = ty;
                    N[d].steps = N[c].steps+1;
                }
            }
        }
        if (F==1)
            break;
    }
}

int main()
{
    int i,j;
    char temp;
    scanf("%d %d\n",&r,&column);//读入行列数
    for (i=1;i<=r;i++)
    {
        for (j=1;j<=column;j++)
        {
            scanf("%c",&temp);
            a[i][j] = temp-48;
        }
        getchar();//读入换行符
    }
    BFS();
    return 0;
}

分析与修改:这里的map是为了保证每一种路径当前所在的坐标位置、步数和内容相对应而设定的,而这一功能也可以存入queue中,这样可以节约map查找所带来的时间;另外,我也没有保证不走回头路,因此,需要设置另一个二维数组,减少走回头路所带来的时间消耗。

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值