HDOJ 1O10 Tempter of the Bone

这道题是一道相当经典的DFS+剪枝。。。做这道题收获比较大,能让你学会几个剪枝技巧。。

一般做这道题的都会把DFS写出来,不难,关键是超时怎么处理,反正在我看了网上的关于剪枝技巧后,当时就有一个感觉,要是别人不跟我说,打死我也想不出来,虽然学起来很简单。。。

下面是别人写的报告:

1    奇偶剪枝:
把矩阵标记成如下形式:
0,1,0,1,0
1,0,1,0,1
0,1,0,1,0
1,0,1,0,1
很明显,如果起点在0 而终点在1 那显然 要经过奇数步才能从起点走到终点,依次类推,奇偶相同的偶数步,奇偶不同的奇数步
在读入数据的时候就可以判断,并且做剪枝,当然做的时候并不要求把整个矩阵0,1刷一遍,读入的时候起点记为(Si,Sj) 终点记为(Di,Dj) 判断总时间与(Di-Xi)+(Dj-Xj)的奇偶性就可以了,是偶数才可以,不是偶数的话直接跳出。。

 

奇偶剪枝的重要思想是:如果从当前位置还需要偶数(奇数)的时间才能到达目标位置,而当前剩余的时间数

为奇数(偶数),那么即刻退出不再沿着纵深方向继续搜索。略微思考便知:奇偶剪枝的效果是立竿见影的!

temp = (t-time) - abs(si-di) - abs(sj-dj);
if( temp<0 || temp&1 )

      continue

2  路径剪枝:D
矩阵的大小是N*M 墙的数量记为wall 如果能走的路的数量 N*M - wall 小于时间T,就是说走完也不能到总的时间的,这显然是错误的,可以直接跳出了

 

#include<iostream>
using namespace std;

char map[9][9];
int directx[4]={1,0,-1,0};
int directy[4]={0,1,0,-1};

int time,flag,n,m,t;

void DFS(int ex,int ey,int dxx,int dyy)
{
 int dx,dy,dtime,temp;
 dtime=time;
 for(int i=0;i<4;++i)
 {
  time=dtime;
  dx=ex+directx[i];
  dy=ey+directy[i];
  if(dx>=0 && dx<n && dy>=0 && dy<m)
  {
   ++time;
   
   if((time>t) || ((time==t) && map[dx][dy]!='D') || ((time<t) && map[dx][dy]=='D'))
    continue;
   if((time==t) && (map[dx][dy]=='D'))
   {
    flag=1;
    return;
   }
   if(map[dx][dy]=='X')
    continue;
   
   temp=(t-time)-abs(dxx-dx)-abs(dyy-dy);
   if(temp<0 || (temp%2)!=0)
    continue;
   map[dx][dy]='X';
   DFS(dx,dy,dxx,dyy);   
  }
  if(flag)
   return;
 }
 if(!flag)
 {
  
  map[ex][ey]='.';
 }
}
int main()
{
 int dx,dy,ex,ey,wall;
 while(cin>>n>>m>>t)
 {
  if(n==0 && m==0 && t==0)
   break;
  memset(map,0,sizeof(map));
  time=flag=wall=0;
  if(n==0 && m==0 && t==0)
   break;
  for(int i=0;i<n;++i)
  {
   for(int j=0;j<m;++j)
   {
    cin>>map[i][j];
    if(map[i][j]=='S')
    {
     ex=i;
     ey=j;
    }
    else if(map[i][j]=='D')
    {
     dx=i;
     dy=j;
    }
    else if(map[i][j]=='X')
     ++wall;
   }
  }
  if((n*m-wall)<=t)
  {
   cout<<"NO"<<endl;
   continue;
  }
  if((t-abs(dx-ex)-abs(dy-ey))<0 || ((t-abs(dx-ex)-abs(dy-ey))%2!=0))
  {
   cout<<"NO"<<endl;
   continue;
  }
  map[ex][ey]='X';
  DFS(ex,ey,dx,dy);
  if(flag)
   cout<<"YES"<<endl;
  else
   cout<<"NO"<<endl;
  
 }
 return 0;
}

 

 

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值