时间限制:1000MS 内存限制:256000KB
题目描述
如下图 12×12 方格图,找出一条自入口(2,9)到出口(11,8)的最短路径。
输入
第一行为一个数 n(2<=n<=12),表示迷宫大小。
第二行为 4 个数,表示起点和终点。
第三起为 n∗n 的矩阵,0 表示通路,1 表示障碍。
输出
第一行为路径(格式见样例)
第二行为总的步数。(数据保证一定有解)
输入样例
12 2 9 11 8 1 1 1 1 1 1 1 1 1 1 1 1 1 0 0 0 0 0 0 1 0 1 1 1 1 0 1 0 1 1 0 0 0 0 0 1 1 0 1 0 1 1 0 1 1 1 0 1 1 0 1 0 0 0 0 0 1 0 0 1 1 0 1 1 1 1 1 1 1 1 1 1 1 0 0 0 1 0 1 0 0 0 0 1 1 0 1 1 1 0 0 0 1 1 1 1 1 0 0 0 0 0 1 0 0 0 0 1 1 1 1 0 1 1 1 1 0 1 0 1 1 1 1 1 1 1 1 0 0 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1
第一眼看到这题有两种想法
1.dfs
从起点向4个方向搜索,用一个数组记录路径,搜到终点时用ans记录下步数,return回去继续递归,如果bs>=ans就返回(剪枝),直到找到答案。
那么用dfs行不行呢?
分析一下:
地图最多到12*12,极端数据是一个12*12的地图,上面全是0,没有障碍,从1,1出发到12,12。
那递归层数将会及其庞大,因为每个点要向4个方向搜索。
而且输出路径较为难处理。
那我们来看一下第二种。
2.bfs
这道题要求输出最短路径,是bfs所擅长的。
同样是搜索最短路径,深搜是直接递归到最后一层,在返回上一层,这样搜当然完整,但效率极低,会产生许多不必要的搜索,浪费时间。
而广搜是层层递进,逐层寻找,找到即为最优解。
还有,这题有个BUG,就是搜索顺序必须是:{{1,0},{-1,0},{0,1},{0,-1}},在出现多个最短路径时,最优解为这种。
然后这题不仅要输出最短步数,还要把路径也输出来,所以还要记录到达的每个点的父节点,输出时反向深搜回去寻找父亲,所以建议手敲队列哟。
#include<bits/stdc++.h>
using namespace std;
int n,xa,ya,xb,yb,a[15][15],b[150][4],fx[4][2]={{1,0},{-1,0},{0,1},{0,-1}};
int h=1,t=1,ans;
bool v[15][15];
int bfs()
{
while(h<=t)
{
for(int i=0;i<=3;i++)
{
int xx=b[h][0]+fx[i][0],yy=b[h][1]+fx[i][1];
if(xx<=n&&xx>=1&&yy<=n&&yy>=1&&!v[xx][yy]&&a[xx][yy]==0)
{
v[xx][yy]=true;
t++;
b[t][0]=xx;
b[t][1]=yy;
b[t][2]=h;//记录父节点
b[t][3]=b[h][3]+1;//步数
if(b[t][0]==xb&&b[t][1]==yb)//找到终点了
return ans=b[t][3];
}
}
h++;
}
}
void dfs(int p)
{
if(p==0) return;//找回起点了,返回(只有起点的父亲是0)
dfs(b[p][2]);//反向搜索父亲
cout<<"("<<b[p][0]<<","<<b[p][1]<<")";
if(p!=t) cout<<"->";
}
int main()
{
cin>>n>>xa>>ya>>xb>>yb;
for(int i=1;i<=n;i++)
for(int j=1;j<=n;j++)
cin>>a[i][j];
b[1][0]=xa,b[1][1]=ya,b[1][2]=b[1][3]=0;//队列初始化
v[xa][ya]=true;
bfs();
dfs(t);//从列的最后一位(答案)回去寻找父亲
cout<<endl;
cout<<ans;
return 0;
}