现在的位置: 首页 > 综合 > 正文

HDU 1010 Tempter of the Bone 【DFS】

2018年01月08日 ⁄ 综合 ⁄ 共 2180字 ⁄ 字号 评论关闭

图搜索的方法有两种,一种是深度优先,一种是广度优先

由于这两种搜索算法在最坏时间的复杂度都接近于穷举,因此在算法中使用剪枝非常重要。

区别

1)回溯法       =   深度优先   +   剪枝

      分支限界   =   广度优先   +   剪枝

2)回溯法适用于在求解空间内求得所有解,通过不断地深入和回溯,每次扩展一个子节点,可以将满足条件的所有解搜出

       分支限界法适用于在求解空间内求得满足条件的一个解或最优解,因为分支限界使用层层扩展的广度优先搜索,每次扩展出所有的子节点,对已经访问过的节点不再重复访问,每一层都以最优关系递进,因此可以满足条件的最优解。

3)实现方式上,在深度优先搜索中通常使用递归方法对某个节点进行深入挖掘,在得到结果或者到达叶节点后返回并清楚节点的已访问状态。广度优先搜索中需要使用到队列,将某个节点的子节点按照某种顺序加入队列中并按顺序取出,扩展子节点后加入队列尾部,对到达的节点加上已访问状态,这样保证可以以某种条件只访问某个节点一次。

剪枝策略

1)最优化剪枝

记录下当前得到的最优值,如果当前所在的节点已经没有可能得到比当前最优值更好的结果,提起回溯。在使用最优化剪枝的过程中,关键是在第一次得到结果或到达叶子节点后记录下得到值作为当前最优值。当后续遍历树的过程中,通过比较如果得到比当前最优值更好的值则更新当前最优值,如果在某个节点中通过比较发现当前所在节点在继续扩展已经无法得到最优解,则剪枝。

2)可行性剪枝

可行性剪枝一般需要根据问题的理解来进行,需要对问题有深刻的理解同时需要敏锐的观察和思考。对于某个具体问题,当运行到某个节点后根据问题信息可以判断是不可行则不需要继续扩展。比较典型的可行性剪枝是奇偶剪枝。

 

思路:

       注意:题目意思不是要求在T秒之前到达门口,不能用BFS,所以要求到达门口的所有情况中刚好在T时刻到达门口的一种情况。  

   AC代码:   

#include<iostream>
#include<cmath>
using namespace std;
char map[8][8];
int viste[8][8];
int fx[4]={1,-1,0,0},fy[4]={0,0,1,-1};
int n,m,T;
int sx,sy,dx,dy;
int DFS(int tx,int ty,int step)
{
	int i;
	int x,y;
    if(tx==dx&&ty==dy&&step==T)
	{
	     return 1;
	}
	if(step>=T)
	{
	     return 0;
	}/*剪枝一:如果step>T直接cut,至于等于T,是因为没有到达门口,如果到达门口上一个if就返回了*/
	if(T-step<(abs(tx-dx)+abs(ty-dy)))
	{
	     return 0;
	}/*剪枝二:如果T-step比当前位置到门口的距离还小的话,那么到达门口时的step肯定大于了T,所以cut*/
	if((T-step-(abs(tx-dx)+abs(ty-dy)))%2)
	{
	     return 0;
	}/*剪枝三:T-step与(abs(tx-dx)+abs(ty-dy))之差肯定要满足偶数,因为例如:当之差为0,表明从当前位置到门口没有遇到障碍物,
	可以即时到达,当差为1,那么肯定会遇到障碍物,然后转弯多走一步,但是转弯回来到达门口也需要一步
	例如:
	0 0 0 0 0
	3 0 1 0 4
	假设狗的当前位置在3,门在4,T-step=5,(abs(tx-dx)+abs(ty-dy))=4,此时差为1,当狗走到3右边的0位置时,肯定要上走一步,数
	一下,从3到4的位置话,要6步,所以T-step必须至少为6,之差为2,因为如果中途再有障碍物的话,还得多走一步,但是走的返回来也的多走一
	步,所以之差必定为偶数*/
	for(i=0;i<4;i++)
	{
	    x=tx+fx[i];
		y=ty+fy[i];
		if(x>=1&&x<=n&&y>=1&&y<=m&&viste[x][y]==0&&map[x][y]!='X')
		{
		    viste[x][y]=1;
			if(DFS(x,y,step+1))
			{
			    return 1;/*递归返回*/
			}
		     else viste[x][y]=0;
		}
	}
	return 0;
}
int main()
{
	int i,j;
	int k;
    while(cin>>n>>m>>T)
	{
		k=0;
		if(n==0&&m==0&&T==0)break;
	    for(i=1;i<=n;i++)	
			for(j=1;j<=m;j++)
			{
			    cin>>map[i][j];
				if(map[i][j]=='S')
				{
				   sx=i;
				   sy=j;
				}
				if(map[i][j]=='D')
				{
				   dx=i;
				   dy=j;
				}
				if(map[i][j]=='X')
					k++;
				viste[i][j]=0;
			}
    if(n*m-k<T)cout<<"NO"<<endl;/*剪枝四:如果可以走的房间数少于T的话,再这么也在T之前到达门口,所以cut*/
	  else
	  {
	     viste[sx][sy]=1;
		 if(DFS(sx,sy,0))
			cout<<"YES"<<endl;
		    else cout<<"NO"<<endl;
	  }
	}
    return 0;
}
/*不知道为什么在杭电上提交要用C++的输入,输出,scanf不行,即使用了getchar(),所以以后WS后,可以尝试把输出流和输入流改成C++
   特别是char和int交替输入时*/

 

抱歉!评论已关闭.