刚开始看到这个题,我第一个想到的是bfs,都是经典套路了,遇到距离最短就用bfs,但是求解的过程不是很顺利
因为之前用递归实现了类似bfs的一种方式,就是标记是否走过,然后以前是类似于flood fill填充吧,就是求某一区间可以走多少个格子,或者某一封闭区间的面积。
代码如下
#include<iostream>
#include<algorithm>
using namespace std;
const int N=210;
const int Inf=0x3f3f3f3f;
int n,m,sx,sy,flag=0;
char g[N][N];
int dx[4]={
1,-1,0,0} ,dy[4]={
0,0,1,-1};
void bfs(int x,int y,int b)
{
if(g[x][y]=='E')
{
flag=min(flag,b);return;
}
g[x][y]='#';
for(int k=0;k<4;k++)
{
int tx=x+dx[k];
int ty=y+dy[k];
if(tx<0||ty<0||tx>=n||ty>=m)
continue;
if(g[tx][ty]!='#')
bfs(tx,ty,b+1);
}
return;
}
int main(void)
{
int T;
cin>>T;
while(T--)
{
cin>>n>>m;
for(int i=0;i<n;i++)
cin>>g[i];
for(int i=0;i<n;i++)
for(int j=0;j<m;j++)
if(g[i][j]=='S')
{
sx=i;sy=j;break;
}
flag=Inf;
bfs(sx,sy,0);
if(flag!=Inf)
cout<<flag<<endl;
else
cout<<"oop!"<<endl;
}
}
然后结果
WA
后来我的仔细分析下,用递归可以实现bfs的某些功能(比如说填充),但是没法实现保存走过的点,并从这些节点找下一个节点。因为题目要求最小距离。我想到了平时标记的book改成dist,这样表示已经走过的距离还能表示是否走过,于是,我写出了成功AC的代码。
#include<iostream>
#include<algorithm>
#include<queue>
#include<cstring>
using namespace std;
#define x first
#define y second
typedef pair<int,int> PII;
const int N=210;
int n,m,sx,sy;
char g[N][N];
int dist[N][N];
int dx[4]={
0,1,0,-1},dy[4]={
1,0,-1,0};
int bfs(int a,int b)
{
memset(dist,-1,sizeof(dist));
PII l;
l.x=a;l.y=b;
dist[a][b]=0;
queue<PII> q;
q.push(l);
while(q.size())
{
auto t=q.front();
q.pop();
for(int i=0;i<4;i++)
{
int tx=t.x+dx[i];
int ty=t.y+dy[i];
if(tx<0||ty<0||tx>=n||ty>=m||dist[tx][ty]!=-1||g[tx][ty]=='#')
continue;
if(g[tx][ty]=='E')
return dist[t.x][t.y]+1;
dist[tx][ty]=dist[t.x][t.y]+1;
q.push({
tx,ty});
}
}
return 0;
}
int main(void)
{
int T;
cin>>T;
while(T--)
{
cin>>n>>m;
for(int i=0;i<n;i++) cin>>g[i];
for(int i=0;i<n;i++)
for(int j=0;j<m;j++)
if(g[i][j]=='S')
{
sx=i;sy=j;break;
}
if(bfs(sx,sy))
cout<<bfs(sx,sy)<<endl;
else
cout<<"oop!"<<endl;
}
}