关于剪枝的思考 ——由hdu1010 dfs+剪枝所想到的

        这道题思路不难,就是剪枝要要求很高,否则老是TLE。

 dfs+剪枝设计思路:

        1,要求的是正好T步到达,不多也不少,所以深度搜索控制的一大条件就是控制步数;

         2,对于剪枝,有这么几个点:

              (1)步数达到T且成功找到Door的,置success为1,同时完成了本题目的要求,结束本次递归 return,并将success是否为1作为本递归函数的结束条件从而达到剪枝的目的;

              (2)步数达到T但没有找到Door的,return;

              (3)提前到达了Door,但步数还没到达T的,return;

              (4)检测本次递归中距离目标的距离为多少步,记为num,然后计算出还有多少步必须要走,记为k,如果num>k,则必然不能到达,return;如果num<k,说明到达目标绰绰有余,还必须绕圈以消耗掉多余的步数,比如下一个格子就可以到目标了,但是因为规定的步数还大于1必须走完,所以不能直接到Door,必须多绕,这样的话会发现,多绕了一个格子,这个格子就不能再走了,再想到达Door就必须再绕两个其他没走过的格子,相比直接到达就多绕了两个格子,所以要求 (num-k) 必须为大于等于2的偶数(这了大家可以亲自试试),如果不是偶数,return ;                       实测发现这是一个很有效的剪枝,可以一举解决TLE的问题,将时间复杂度减小的500ms内。

        关于剪枝,要想真正做好,就得深挖题意,找到那些真正能控制时间的因素,尽力把递归层数控制在一个很小的范围内,这说起来容易做起来难,要么就是多做点此类型的题目,自然能熟能生巧,所谓天道酬勤,就是这个意思吧。

下面是代码:

#include<iostream>
#include<cstring>
#include<cmath>

using namespace std;

int a[10][10];
char b[10];
int flag[4][2]={0,-1,0,1,-1,0,1,0};
int startx=0;
int starty=0;
int endx=0;
int endy=0;
 int M=0,N=0,T=0;
int success=0;
void dfs(int x,int y,int cnt)//cnt为目前(x,y)当前位子的跳数
{
	if(success==1)
		return ;
   if( cnt==T && x==endx && y==endy)
   {

     success=1;
	 return ;
   }
	if(x==endx && y==endy)
	{
	 return;
	}
   if(cnt==T)
   {
     return ;
   }
   int num=abs(x-endx)+abs(y-endy);//要到达Door此时至少还要走的步数
   int k=T-cnt;
   if(num>k || (k-num)%2!=0)//重要剪枝
	   return;
   for(int i=0;i<4;i++)
   {
	   int p1=x+flag[i][0];
	   int p2=y+flag[i][1];
	   if(p1<N && p1>=0 && p2<M && p2>=0 && a[p1][p2]!=0)
	   {   
		 
		   a[p1][p2]=0;
		   dfs(p1,p2,cnt+1);
           a[p1][p2]=1;
	   }
   }
   return ;
}
int main()
{
 memset(b,'\0',sizeof(b));
 memset(a,0,sizeof(a));

 while(scanf("%d%d%d",&N,&M,&T)&&( N!=0 && M!=0 && T!=0))
 {
	 success=0;
	 int t=N;
	 int i=-1;
  while(t--)
		{
	         i++;
			 scanf("%s",b);
			//gets(b);不要用gets()
	       for(int j=0;j<M;j++)
		   {
			if(b[j]=='.')
		       a[i][j]=1;
		    else if(b[j]=='S')
			{
				 a[i][j]=0;
				 startx=i;
				 starty=j;
			}
		    else if(b[j]=='D')
			{
			   a[i][j]=1;
			   endx=i;
			   endy=j;
			}
			else
				a[i][j]=0;
		   }
		memset(b,'\0',sizeof(b));
	}//输入完毕
	 
    dfs(startx,starty,0);
	 
	if(success)
		printf("YES\n");
	else
		printf("NO\n");
	
	memset(a,0,sizeof(a));

 }
 return 0;
}


评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值