题目地址
贪吃蛇 link
https://ac.nowcoder.com/acm/contest/9986/I
链接:https://ac.nowcoder.com/acm/contest/9986/I
来源:牛客网
题目描述
无限增长的贪吃蛇小游戏:
在一个n*m的迷宫中,有一条小蛇,地图中有很多围墙,猥琐的出题者用“#”表示,而可以走的路用“.”表示,小蛇他随机出生在一个点上,出生点表示为“S”,他想抵达的终点表示为“E”,小蛇有一个奇怪的能力,他每走一格便会增长一格,即他走了一格后,他的尾巴不会缩回。
小蛇想知道他怎么到达他想去的地方,请你帮助他。
PS:每格长1米,贪吃蛇规定不能撞墙,不能咬自己的身体。
输入描述:
第一行:输入N,M;
第二行:输入S的坐标Xs,Ys,E的坐标Xe,Ye;
后面的N行:
每行输入M个数,描述每一行的情况。
输出描述:
输出一个数,小蛇到达终点的最短距离(单位:cm),若无法达到,输出-1
示例1
输入
复制
3 3
1 1 3 3
.#.
.#.
…
输出
复制
400
示例2
输入
复制
5 5
1 1 5 5
…###
.#…
.#.#.
.#.#.
…#.
输出
复制
1400
备注:
对于 100% 的数据:1\le n,m\le 1001≤n,m≤100 ,保证起点不是围墙。
思路
*1.*bfs与dfs都可以解决,但是不同的方式都会遇见相同的问题:距离怎么表示,如何求最近的距离
*2.*对于bfs 他每一次将可以移动的地方记录下来,也就是说一个点到周围可以移动的点他都会先遍历一遍,然后再走,所以我们可以吧vis数组改一下(本来是用来记录是否走过,防止来回移动),将他改成在记录改点的距离的数据,也就是说vis是记录这个点是起点移动几步得到的。
代码如下:
#include
using namespace std;
const int M = 110;
int vis[110][110];
int m,n,xs,ys,ye,xe,ok; //初始数据
char Map[110][110];
struct node{
int xx;
int yy;
};//表示坐标
int dx[4] = {
-1,0,1,0};
int dy[4] = {
0,-1,0,1};
void bfs(){
queue<node> q;
node beg,ll;//beg是将起点变成node的类型,不然queue不认识,见面就打架
//ll也是转换,就是新得到出来的点 转换,详情往下看
beg.xx=xs;
beg.yy=ys;
q.push(beg);
vis[xs][ys] = 0;
while(!q.empty()){
node top = q.front();
q.pop();
if(top.xx==xe&&top.yy==ye) {
ok = 1;
return ;
}
for(int i = 0;i<4;i++){
int xx = top.xx+dx[i];
int yy = top.yy+dy[i];
if(xx>=1&&xx<=n&&yy>=1&&yy<=m){
if(vis[xx][yy] == -1&&Map[xx][yy]!='#'){
vis[xx][yy] = vis[top.xx][top.yy]+1; //与普通bfs区别 就在这,没错,理解这里就okk了。
ll.xx = xx;
ll.yy = yy;
q.push(ll);
}
}
}
}
}
int main(){
scanf("%d%d%d%d%d%d",&n,&m,&xs,&ys,&xe,&ye);
for(int i = 1;i<=n;i++){
scanf(" ");
for(int j = 1;j<=m;j++)
scanf("%c",&Map[i][j]);
}
memset(vis,-1,sizeof vis);
bfs();
if(!ok) cout<<-1<<endl;
else
cout<<(vis[xe][ye])*100<<endl;
return 0;
}
哎呀,说那么多,其实只要理解了vis[xx][yy] = vis[top.xx][top.yy]+1就可以明白了。
*3.*dfs要注意一条路走过之后,还能被另一种方案走,也就是一个点可能被用多次,所有当这个点遍历完,还是要出来的。
代码如下
#include
using namespace std;
int n,m,xs,ys,xe,ye; //初始读入
const int INF = 0x4f4f4f4f; //设置最大值
int vis[110][110]; //记录是否走过
char Map[110][110];
struct node{
int xx,yy;
bool operator==(const node& nw){
//定义 相等
return (nw.xx==xx&&nw.yy==yy);
}
}be,en; //起点和终点
int maxs = INF,ok;
int dx[4]={
0,1,0,-1};
int dy[4]={
1,0,-1,0};
void dfs(node t,int dis){
if(t == en){
maxs = min(dis,maxs);
ok = 1;
}
int xx,yy;
vis[t.xx][t.yy] = 1;
for(int i = 0;i<4;i++){
xx = t.xx+dx[i];
yy = t.yy+dy[i];
if(xx>0&&xx<=n&&yy>0&&yy<=m&&vis[xx][yy]==0&&Map[xx][yy]!='#'){
node go;
go.xx=xx;
go.yy=yy;
vis[xx][yy] = 1;
dfs(go,dis+1);
//与简单的dfs区别就是这了,没错!!!
vis[xx][yy] = 0; //出来后表示回去,因此这条路也就不能算走过了
}
}
}
int main(){
scanf("%d%d",&n,&m);
scanf("%d%d%d%d",&xs,&ys,&xe,&ye);
be.xx = xs;
be.yy = ys;
en.xx = xe;
en.yy = ye;
for(int i = 1;i<=n;i++){
scanf(" ");
for(int j = 1;j<=m;j++){
scanf("%c",&Map[i][j]);
}
}
dfs(be,0);
if(ok)
cout<<maxs*100<<endl;
else cout<<-1<<endl;
return 0;
}
又到了让我期待的 总结
对比上面两个代码,会发现,bfs只要第一次找到了出口,就是最短的距离,而dfs还是要跑完整张图,可能有优化方法我没想到。。。
总而言之,建议在于最短路程相关的遍历时还是用bfs更好,更方便。