• DFS-hdu-2821-Pusher


    题目链接:

    http://acm.hdu.edu.cn/showproblem.php?pid=2821

    题目意思:

    给一个n*n的矩阵,里面有些位置是空的,有些位置有箱子(a代表一个箱子,b代表两个,依此类推)。让你选择一个空位置作为起点,然后每步选择一个方向(上,下,左,右)走,直到碰到箱子为止,然后将此位置的箱子移走一个,剩下的箱子全部合并到下一位置。要求:必须与箱子隔超过1个位置的时候才能移。

    求一个开始位置使得能够移除所有的箱子,并输出行走路线。

    经数据检测两点注意:1、不含边缘位置超过一个箱子的情况,2、保证有解。

    解题思路:

    枚举开始位置,DFS深搜,有一条路径能全部移走箱子,则输出。

    注意保存回溯现场(不要用全局变量来保存现场,因为在递归调用的时候会覆盖原来保存的现场,wa了好几次)。

    代码:

    #include<iostream>
    #include<cmath>
    #include<cstdio>
    #include<cstdlib>
    #include<string>
    #include<cstring>
    #include<algorithm>
    #include<vector>
    #include<map>
    #include<set>
    #include<stack>
    #include<list>
    #include<queue>
    #define eps 1e-6
    #define INF 0x1f1f1f1f
    #define PI acos(-1.0)
    #define ll __int64
    #define lson l,m,(rt<<1)
    #define rson m+1,r,(rt<<1)|1
    //#pragma comment(linker, "/STACK:1024000000,1024000000")
    using namespace std;
    
    /*
    freopen("data.in","r",stdin);
    freopen("data.out","w",stdout);
    */
    
    char save[30][30],save1[30][30];
    int c,r,dir[4][2]={{-1,0},{0,1},{1,0},{0,-1}};
    int lim,cnt;
    char di[4]={'U','R','D','L'};
    
    struct Inf
    {
       int x,y;
    }s;
    
    bool iscan(Inf & tt,int dd)
    {
       int xx=tt.x+dir[dd][0],yy=tt.y+dir[dd][1];
    
       if(xx<0||xx>=r||yy<0||yy>=c) //下一步出界了,不行
          return false;
       if(save1[xx][yy]!='.') //下一步就是箱子不行
          return false;
       while(save1[xx][yy]=='.') //在该方向走,直到靠近箱子为止
       {
          xx=xx+dir[dd][0],yy=yy+dir[dd][1];
          if(xx<0||xx>=r||yy<0||yy>=c)//走出去了,不行
             return false;
       }
       if(save1[xx][yy]=='a')//该位置只有一个箱子
       {
          cnt++;
          save1[xx][yy]='.';
          tt.x=xx,tt.y=yy;
          return true;
       }
       else   //该位置有多个箱子
       {
          int x=xx+dir[dd][0],y=yy+dir[dd][1];
          if(x<0||x>=r||y<0||y>=c) //边缘有多个箱子的情况
          {
             //cnt++;
             //tt.x=xx,tt.y=yy;
             //save1[xx][yy]=save1[xx][yy]-1;
             //return true; //两种写法都可以,其他写法也行,因为测试数据中不存在这种情况
             return false;
          }
          cnt++;
          tt.x=xx,tt.y=yy;
          if(save1[x][y]!='.') //下一位置如果不是.的话,直接合并
             save1[x][y]=save1[x][y]+save1[xx][yy]-'a';//注意-'a'
          else    //下一位置是.的话,直接拿过来
             save1[x][y]=save1[xx][yy]-1;
          save1[xx][yy]='.';
          return true;
       }
    }
    bool flag;
    string an;
    
    void dfs(Inf cur,string ans)
    {
       if(flag) //已找到一条路径
          return ;
       char tt[30][30];//注意保存现场时要用局部变量
       for(int i=0;i<4;i++) //沿四个方向走
       {
          memcpy(tt,save1,sizeof(save1));
          Inf tmp=cur;
          int temp=cnt; //便于回溯的时候,其他没有改变
          /*if(test)
          {
             for(int j=0;j<r;j++)
                printf("%d %s
    ",j,save1[j]);
          }*/
          if(!iscan(tmp,i))
             continue;
         /* if(test)
          {
             printf("%d %d->%d %d cnt:%d
    ",cur.x,cur.y,tmp.x,tmp.y,cnt);
             putchar('
    ');
             for(int j=0;j<r;j++)
                printf("%d %s
    ",j,save1[j]);
          }*/
          string tm=ans;
          tm+=di[i];
          if(cnt==lim) //找到了一条路径能全部移完
          {
             an=tm;
             flag=true;
             return ;
          }
          dfs(tmp,tm);
          cnt=temp;  //回溯
          memcpy(save1,tt,sizeof(tt));
       }
    }
    
    int main()
    {
       while(~scanf("%d%d",&c,&r))
       {
          lim=0;
          for(int i=0;i<r;i++)
          {
             scanf("%s",save[i]);
             for(int j=0;j<c;j++)
                if(save[i][j]!='.')
                   lim+=(save[i][j]-'a'+1); //统计箱子个数
          }
          //putchar('
    ');
          flag=false;
          for(int i=0;i<r&!flag;i++)
             for(int j=0;j<c&&!flag;j++)
             {
                if(save[i][j]!='.') //枚举开始位置,注意开始位置不为
                   continue;
                s.x=i,s.y=j;
                cnt=0;
                memcpy(save1,save,sizeof(save));
                dfs(s,"");
                if(flag)
                {
                   printf("%d
    %d
    ",i,j);
                   cout<<an<<endl;
                }
             }
       }
       return 0;
    }
    


  • 相关阅读:
    【leetcode-100】 简单 树相关题目
    【leetcode-101】 对称二叉树
    【2】【leetcode-105,106】 从前序与中序遍历序列构造二叉树,从中序与后序遍历序列构造二叉树
    【leetcode-102,107,103】 二叉树的层次遍历
    iOS开发
    对称加密和不对称加密原理
    uiimageview 异步加载图片
    如何让IOS中的文本实现3D效果
    SDWebImage使用,图片加载和缓存
    ios 图片处理( 1.按比例缩放 2.指定宽度按比例缩放
  • 原文地址:https://www.cnblogs.com/jiangu66/p/3238886.html
Copyright © 2020-2023  润新知