洛谷P1238 走迷宫

题目描述

有一个m*n格的迷宫(表示有m行、n列),其中有可走的也有不可走的,如果用1表示可以走,0表示不可以走,文件读入这m*n个数据和起始点、结束点(起始点和结束点都是用两个数据来描述的,分别表示这个点的行号和列号)。现在要你编程找出所有可行的道路,要求所走的路中没有重复的点,走时只能是上下左右四个方向。如果一条路都不可行,则输出相应信息(用-1表示无路)。

优先顺序:左上右下

输入格式

第一行是两个数m,n(1<m,n<15),接下来是m行n列由1和0组成的数据,最后两行是起始点和结束点。

输出格式

所有可行的路径,描述一个点时用(x,y)的形式,除开始点外,其他的都要用“一>”表示方向。

如果没有一条可行的路则输出-1。

输入输出样例

输入 #1
5 6
1 0 0 1 0 1
1 1 1 1 1 1
0 0 1 1 1 0
1 1 1 1 1 0
1 1 1 0 1 1
1 1
5 6
输出 #1
(1,1)->(2,1)->(2,2)->(2,3)->(2,4)->(2,5)->(3,5)->(3,4)->(3,3)->(4,3)->(4,4)->(4,5)->(5,5)->(5,6)
(1,1)->(2,1)->(2,2)->(2,3)->(2,4)->(2,5)->(3,5)->(3,4)->(4,4)->(4,5)->(5,5)->(5,6)
(1,1)->(2,1)->(2,2)->(2,3)->(2,4)->(2,5)->(3,5)->(4,5)->(5,5)->(5,6)
(1,1)->(2,1)->(2,2)->(2,3)->(2,4)->(3,4)->(3,3)->(4,3)->(4,4)->(4,5)->(5,5)->(5,6)
(1,1)->(2,1)->(2,2)->(2,3)->(2,4)->(3,4)->(3,5)->(4,5)->(5,5)->(5,6)
(1,1)->(2,1)->(2,2)->(2,3)->(2,4)->(3,4)->(4,4)->(4,5)->(5,5)->(5,6)
(1,1)->(2,1)->(2,2)->(2,3)->(3,3)->(3,4)->(2,4)->(2,5)->(3,5)->(4,5)->(5,5)->(5,6)
(1,1)->(2,1)->(2,2)->(2,3)->(3,3)->(3,4)->(3,5)->(4,5)->(5,5)->(5,6)
(1,1)->(2,1)->(2,2)->(2,3)->(3,3)->(3,4)->(4,4)->(4,5)->(5,5)->(5,6)
(1,1)->(2,1)->(2,2)->(2,3)->(3,3)->(4,3)->(4,4)->(3,4)->(2,4)->(2,5)->(3,5)->(4,5)->(5,5)->(5,6)
(1,1)->(2,1)->(2,2)->(2,3)->(3,3)->(4,3)->(4,4)->(3,4)->(3,5)->(4,5)->(5,5)->(5,6)
(1,1)->(2,1)->(2,2)->(2,3)->(3,3)->(4,3)->(4,4)->(4,5)->(5,5)->(5,6)


思路:就是一个深搜,不过要记录前面从哪里走来的,那么只需要开一个pre数组来记录前面的坐标即可。pre[i][j][0]记录点(i,j)前一个点的横坐标,pre[i][j][1]则记录纵坐标。

代码:
#include<iostream>
#include<cstdio>
#include<algorithm>
#include<cstring>
#include<cmath>
using namespace std;
int m,n,sx,sy,lx,ly,f;
int dy[5]={0,-1,0,1,0};//这里是最细节的地方,因为在这种行列的矩阵里,经常会出现或者是大部分都是x表示纵坐标而y表示横坐标,但是我忽略了这一点,由于这个题要求优先级了,所以顺序不对是不行的。经过大佬fys的指点,我才成功地A了这个题,所以这个时候就要把x和y的数组换一下,左边就是y-1,而下边则是x+1,这里又是一个细节,因为左上角的点是(1,1),所以往下走其实纵坐标(x)要+1,往上走则要-1
int dx[5]={0,0,-1,0,1};
int a[20][20];
int pre[20][20][2];
void print(int x0,int y0)
{
    if(pre[x0][y0][0]!=sx||pre[x0][y0][1]!=sy)//由于第一个起点也要输出但是前面没有箭头,所以要特别输出,不能在这个函数里,所以第二个点的时候就停止 print(pre[x0][y0][0],pre[x0][y0][1]);//如果它前面还有点的话,那么继续递归。一定要先递归再输出,这样才能从第一个点从前往后输出
    cout<<"-"<<">"<<"("<<x0<<","<<y0<<")";//print函数用来输出结果
}
void dfs(int x1,int y1)
{
    if(x1==lx&&y1==ly)
    {
        f=1;//f用来判断有没有路径到达终点,如果没有输出-1
        cout<<"("<<sx<<","<<sy<<")";//如果找到了这个点,那么输出并且特别输出起点
        print(lx,ly);
        cout<<endl;//输出回车别忘了
        return;
    }
    a[x1][y1]=0;
    for(int i=1;i<=4;i++)
    {
        int x=x1+dx[i];
        int y=y1+dy[i];
        if(a[x][y]==1&&x>=1&&x<=n&&y>=1&&y<=m)
        {
            a[x][y]=0;
            pre[x][y][0]=x1;
            pre[x][y][1]=y1;
            dfs(x,y);
            a[x][y]=1;//这就是当初我死活都学不会的回溯,每次递归完之后你要把它恢复原状,以便下一次搜索时还是初始状态
            pre[x][y][0]=0;
            pre[x][y][1]=0;
        }
    }
}
int main()
{
    cin>>n>>m;
    for(int i=1;i<=n;i++)
        for(int j=1;j<=m;j++)
            cin>>a[i][j];
    cin>>sx>>sy>>lx>>ly;
    if(a[sx][sy]==0||a[lx][ly]==0)
    {
        cout<<-1<<endl;
        return 0;
    }
    dfs(sx,sy);//搜索
    if(f==0)//如果没有到达终点,那么输出-1
        cout<<-1<<endl;
    return 0;
}

 

posted @ 2020-06-03 17:33  徐明拯  阅读(232)  评论(0编辑  收藏  举报