洛谷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; }