DFS——关于洛谷P2802-回家的思考

  题目链接:https://www.luogu.com.cn/problem/P2802

  解题主要思路:1.通过理解题意和观察到题目的变量范围:1<=n,m<=9,便可推断出本题大致要用DFS。

  AC代码展示:   

  ——note:题意简简单单,但实际写起来注意事项还蛮多的。 

 1 #include<bits/stdc++.h>
 2 using namespace std;
 3 int n,m;
 4 int s[100][100];
 5 //int book[100][100];  book数组不用开  因为题目没有说不能走重复的路径
 6 int sx,sy;
 7 int dis[4][2]={{-1,0},{0,1},{1,0},{0,-1}};
 8 int hp1=6;
 9 int minn=999999;  //原则上minn设置成比m*n大一点的数
10 void dfs(int t,int x,int y,int hp){
11     if(t>=minn){   //剪枝策略   减去不用的循环
12         return;
13     }
14     if(s[x][y]==3){  //终点判断
15         minn=min(minn,t);
16         return;
17     }
18     if(t>=(n*m/2)){  //剪枝策略  不然会在两个鼠标处来回逛 无限循环
19         return;
20     }
21     if(s[x][y]==4){  //捡起鼠标
22         hp=6;
23     }
24     if(hp==1){  //剪枝策略  
25         return;
26     }
27     for(int i=0;i<4;i++){
28         int x1=x+dis[i][0];
29         int y1=y+dis[i][1];
30         if((x1>=0&&x1<n)&&(y1>=0&&y1<m)&&s[x1][y1]!=0&&s[x1][y1]!=2){//别回到终点  别撞到墙上
31             dfs(t+1,x1,y1,hp-1);  //hp 和 t不建议设成常量  因为这两个量是随着枚举状态变化而变化  设成常量会出错
32         }
33     }
34 }
35 int main(){
36     scanf("%d%d",&n,&m);
37     for(int i=0;i<n;i++){
38         for(int j=0;j<m;j++){
39             scanf("%d",&s[i][j]);
40             if(s[i][j]==2){
41                 sx=i;
42                 sy=j;
43             }
44         }
45     }
46     dfs(0,sx,sy,6);
47     if(minn==999999){//  不能设置成0  要设置成原来的量  因为可以这么理解  没到终点的话就不会改变minn
48         cout<<-1;
49     }else{
50         cout<<minn;
51     }
52 }

  注意事项:1.题目上并没有说不可以走重复的路径,而且从题意也可以推测出有些案例必须要走重复的路径,所以标记数组即book数组就可以不用开了,这就要注意别让程序无限递归!,就是在两个鼠标之间无                      限走来走去

                    2.为了解决无限递归的问题,这就要设置dfs函数的参量step(步数)的上限了,一般按经验是取到n*m/2为最大值。

                    3.判断是否捡到鼠标的放置也要有讲究,要位于“处理区”,而且是在位于特定位置上,必须要判断hp==1前面。

                    

 

                    4.我一开始写本程序的时候就想让hp(生命值)设置成全程变量,但这样写会wa,因为hp是随着枚举的状态的变化而变化,所以更好的选择是放在函数的形参当中,t(步数也类似)。

                    5.minn等于原值时才是没有路径可以回家,可以这么理解,因为没有路径可以回家,也就是无法更新minn,所以minn为初值,反过来也一样,故是一个充要条件。

                    6.即使注意到了以上几点,还是会超时tle,必须要在开头加个判断if,即如果t>=minn,就放弃它,避免做无用功,这是一个简单的剪枝。

 

posted @ 2021-05-07 19:59  江间暮云  阅读(86)  评论(0)    收藏  举报