hdoj--1010<dfs+奇偶剪枝>
题目链接:http://acm.hdu.edu.cn/showproblem.php?pid=1010
题目描述:在n*m的矩阵中,有一起点和终点,中间有墙,给出起点终点和墙,并给出步数,在该步数情况下走到终点,走过的点不能再走;
题目要点:dfs+奇偶剪枝;输入;
本题用dfs可以做出结果,但是会超时,需要用到就剪枝,来减去大部分的可能;
奇偶剪枝:
方格中起点(tx,ty)和终点(dx, dy)最小步骤是minstep=abs(tx-dx)+abs(ty-dy);
给定步数t,从起点走到终点,如果t < minstep,不可以,如果t =minstep,一部也没有多走,如果t> minstep,则多走了extra步,extra=t-minstep;
经过推导可以证明多走的一定是偶数步,即extra一定是偶数。
现在,如果已经走了n步,到达了(x,y)的位置,现在距离终点最小距离是L=abs(x-dx)+abs(y-dy); 现在还可以走的是 t - n 步,如果(t-n)<0,则不能走到地方,如果(t- n)-L 是奇数,则无法多走出偶数步到达指定位置,所以这样的是不行的;
同时,本题时间卡的比较紧,使用dfs事实上是构造可行方案树,有m步最后就有2^m个叶子,所以在进入下一层dfs之前判断是否可行可以减少一大部分叶子;
代码如下:
1  2 #include<iostream> 3 #include<math.h> 4 5 using namespace std; 6 int n,m,t,k,dx,dy; 7 int p,q,tm; 8 int dir[4][2]={{-1,0},{0,1},{1,0},{0,-1}};//构建位置数组,遍历周围四个点; 9 char a[8][8]; 10 void dfs(int x,int y,int count) 11 { 12 int temp; 13 temp=t-count-abs(dx-x)-abs(dy-y); 14 if(temp<0||temp%2==1) //判断是否有偶数步,没有就退出; 15 return ; 16 17 int tx,ty; 18 for(int i=0;i<4;i++) //循环遍历周围的四个结点,先预判是否超出边界,然后判断是否找到结果,如果找到就不用在进去了; 19 { 20 tx=x+dir[i][0]; 21 ty=y+dir[i][1]; 22 if(a[tx][ty]=='D'&&count==t-1) 23 { 24 k=1; 25 return ; 26 } 27 if(a[tx][ty]=='.'&&(tx>=0&&tx<n)&&(ty>=0&&ty<m)) 28 { 29 a[tx][ty]='X'; 30 dfs(tx,ty,count+1); 31 a[tx][ty]='.'; 32 if(k==1) //如果没有确定的结果就进去dfs,出来后判断是否有结果了,这样可以减少dfs的步骤; 33 return ; 34 } 35 } 36 37 } 38 int main() 39 { 40 while(cin>>n>>m>>t&&n!=0||m!=0||t!=0) 41 { 42 tm=0; 43 for(int i=0;i<n;i++) 44 { 45 for(int j=0;j<m;j++) 46 { 47 cin>>a[i][j]; 48 if(a[i][j]=='S') 49 { 50 p=i;q=j; 51 } 52 if(a[i][j]=='D') 53 { 54 dx=i;dy=j; 55 } 56 if(a[i][j]=='X') 57 tm++; 58 } 59 } 60 k=0; 61 if(n*m-tm<=t) //开始判断是否有足够的空来走,没有就直接跳过dfs; 62 { 63 printf("NO\n"); 64 continue; 65 } 66 dfs(p,q,0); 67 if(k==1) 68 printf("YES\n"); 69 else 70 printf("NO\n"); 71 } 72 return 0; 73 }
顺便贴几个dfs的题目
hdoj: 1010 1015 1016 1045 1175 1181 1241 1272 1421 1455 1518 1728