poj-3009-Curling 2.0-dfs

题目太长就不贴了,题意:

上下左右四联通块,2表示起点,3表示终点,1为block,0为空地,每动一次冰壶,冰壶就会向推动的方向一直移动,直到碰到block或出界,如果碰到block就在block前停下来,同时block消失,如果出界则失败,输出-1,同时,如果在10次推动内都没达到终点也失败,输出-1。如果成功,则输出最少推动次数。


思路:

有四种情况:1,冰壶起点周围没有空地,不能推动,失败;   2,冰壶周围有空地可以移动,则进行对周围进行dfs,情况有三,①直接遇到终点、②碰到block、③出界。


总结:

被这题难住的地方有  :①冰壶可以一直移动,②block会消失,所以如果dfs不成功,还要复原,③对于一开始就不能移动的冰壶做判断。对于第一种情况用一趟while()一直对一个方向更新坐标直到边界条件或下次dfs起点,就解决了;对于第二种情况,可以看下面的AC代码,其实每次冰壶碰到block之后让block消失,然后重新dfs,但在dfs返回时再复原就好了,这时 ans 已经记录下最少移动次数的信息,对于block存不存在对结果没有影响,自己可以思考一下;情形三,则作一判断   !( nx-dir[i][0] == x && ny-dir[i][1] == y ),具体看下面的代码。

当把上面的情况理清之后,就是一道很基础的dfs了~

下面是AC代码:

#include<iostream>
#include<cstdio>
using namespace std;
#define maxn 30
#define INF 9000
int d[4][2] = { 0,1, 0, -1, 1, 0, -1, 0 };
int bo[maxn][maxn];
int w, h, ans;
bool check(int a, int b)
{
   if(a >= 0 && b >= 0 && a < h && b < w) return true;
   return false;
}
int x;
void dfs(int a, int b, int rec)
{
   if(rec > 10 || rec > ans) return;
   for(int i = 0; i < 4; i++)
   {
      int dx = a + d[i][0];
      int dy = b + d[i][1];
      if(check(dx, dy) && (bo[dx][dy] == 0 || bo[dx][dy] == 2|| bo[dx][dy] == 3)){
         bool flag = 0;//cout<<i<<endl;
         while(bo[dx][dy] != 1 && bo[dx][dy] != 3){
            dx += d[i][0];
            dy += d[i][1];
            if(!check(dx, dy)) {
               flag = 1;
               break;
            }
         }

         if(flag) continue;
         if(bo[dx][dy] == 1) {
            bo[dx][dy] = 0;
            dfs(dx-d[i][0], dy-d[i][1], rec+1);
            bo[dx][dy] = 1;
         }
         if(bo[dx][dy] == 3){
            if(ans > rec) ans = rec;
            return;
         }
      }
   }
}
void work()
{
   int sx, sy;
   for(int i = 0; i < h; i++){
      for(int j = 0; j < w; j++){
         scanf("%d", &bo[i][j]);
         if(bo[i][j] == 2) sx = i, sy = j;
      }
   }
   ans = INF;
   dfs(sx, sy, 1);
   if(ans == INF) printf("-1\n");
   else printf("%d\n", ans);
}
int main()
{
   while(scanf("%d%d", &w, &h) != EOF && h && w){
      work();
   }
   return 0;
}



评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值