这道题被稍微改编当作过去年的期末上机题,也被直接放到了这次这一届的第二次练习赛。当初刚看到这道题时DFS并没有系统的学过,做起来极其费劲。现在学过之后开始实践练习,发现这道题真的是很水。
我的DFS函数中加入了方向,和拐弯数两个参数,作为判断。(其实是放在外面当全局变量自己控制不好的借口orz),并将vi这个数组存储为到达这个位置时最少的拐弯数,这样大于vi到达这里并且vi不是初始值-1的就直接剪枝。
1 #include<cstdio> 2 #include<cstring> 3 using namespace std; 4 int a[1005][1005],n,m,vi[1005][1005],dir[4][2]={{1,0},{-1,0},{0,1},{0,-1}},ci,flag,ei,ej; 5 void dfs(int si,int sj,int d,int x) 6 { 7 if(si==ei&&sj==ej&&x<=2)//看是否成功到达终点 8 {flag=1;return;} 9 if(si<0||si>=n||sj<0||sj>=m||x>2||(x>vi[si][sj]&&vi[si][sj]!=-1)||a[si][sj]!=0||flag==1)//几个预先判断 10 return; 11 else 12 { 13 a[si][sj]=1; 14 vi[si][sj]=x;//注意将vi存储为到这个位置所经历的拐弯数 15 for(int i=0;i<4;i++) 16 { 17 if(i==d)dfs(si+dir[i][0],sj+dir[i][1],i,x);//有两种情况,继续沿着之前的方向前进的话拐弯数不变,不然就+1 18 else 19 dfs(si+dir[i][0],sj+dir[i][1],i,x+1); 20 } 21 a[si][sj]=0; 22 } 23 } 24 int main() 25 { 26 while(scanf("%d%d",&n,&m)) 27 { 28 if(n==0&&m==0) 29 break; 30 int i,j,si,sj; 31 for(i=0;i<n;i++) 32 for(j=0;j<m;j++) 33 scanf("%d",&a[i][j]); 34 scanf("%d",&ci); 35 while(ci--) 36 { 37 memset(vi,-1,sizeof(vi));//将数组初始化为-1这个之后不可能取到的值有助于判断 38 scanf("%d%d%d%d",&si,&sj,&ei,&ej); 39 si--; 40 sj--; 41 ei--; 42 ej--; 43 flag=0; 44 if(a[si][sj]!=a[ei][ej]||(a[si][sj]==0)||a[ei][ej]==0)//如果是不需dfs就能判断的不成立情况就直接continue 45 { 46 printf("NO "); 47 continue; 48 } 49 else 50 { 51 for(i=0;i<4;i++) 52 dfs(si+dir[i][0],sj+dir[i][1],i,0); 53 if(flag) 54 printf("YES "); 55 else 56 printf("NO "); 57 } 58 } 59 } 60 return 0; 61 }
当初做起来非常困难的题目现在可以不到10分钟轻松做出来,进步的喜悦真的是难以描述。还有很多的内容需要学习与练习,继续加油!