Pusher HDU - 2821 细节dfs的另一种写法

Pusher HDU - 2821
看网上的题解都差不多
我来发一篇自己写的dfs,
与网上大多写的dfs不同,是另一种dfs的写法
(感觉更好哦)
题意 有一个RC的方格,‘.’代表空地,‘az’分别代表该处有126个箱子,某人可以从距离箱子至少一个空格处推箱子,推一次此处少一个箱子,如果这个格还有其他箱子,则和它下一个格的箱子合并或到下一个格,朝着某个方向一直推到边界或者遇到箱子不能推为止(即箱子数多于1的堆在边界)才可以换方向,任意输出一种可以把箱子推完的方案,输出推箱子时起点的位置以及推箱子时的方向。
注意:①起点不能有箱子。②必须要隔一个位置才能碰。③碰的箱子在边上时,如果剩下的箱子移出边界,则视为违法的,需要换个方向
思路 细节dfs,先预处理下,将’.'换成数字0,abcd换成对应数字即可
踩坑 别用getchar()一个个读入处理,容易出错!!!
小技巧 双重循环还可以这样退出!!!

这道题主要是细节,细节都写代码里了,看代码吧

#include<iostream>
#include<string>
#pragma comment(linker, "/STACK:102400000,102400000")//解决递归函数多次调用栈溢出问题
using namespace std;
#define Debug(x) cout<<#x<<':'<<x<<endl
typedef long long ll;
#define INF 0x7fffffff//10^9级别,不到2^32
ll gra[33][33],dir[11][2]={0,0,-1,0,0,1,1,0,0,-1};//方向数组
char ar[11]={'0','U','R','D','L'};//记录路径
ll c,r;
string outs;
ll dfs(ll x,ll y,ll cnt,string s,ll d,ll b){//
//x,y是推箱人的坐标,cnt是剩余箱子数量,s是推箱子的路径方向
//d为1 2 3 4,分别表示上右下左,
//b为间隙数,当b>=2时,表明经过了至少一个间隙,才能碰
//dfs找到一条能把箱子都清楚的路径时返回1,否则返回0
    if(x<1 || x>r || y<1 || y>c)  return 0;//当前越界
    if(cnt==0){//箱子全部清除
        outs=s;
        return 1;
    }  
    if(d==0){//推到箱子停止时,d为0,选择方向
        for(ll i=1;i<=4;i++){
            if(dfs(x+dir[i][0],y+dir[i][1],cnt,s+ar[i],i,b+1))  return 1;
        }
    }
    else{//d不为0
        if(gra[x][y]==0){//当前位置是道路
            if(dfs(x+dir[d][0],y+dir[d][1],cnt,s,d,b+1))  return 1;
        }  
        else{//当前位置是与木块重合,即撞到木块,
            if(b<2)  return 0;//如果没有间隙,即必须要隔一个位置才能碰
            if(x+dir[d][0]<1 || x+dir[d][0]>r || y+dir[d][1]<1 || y+dir[d][1]>c){//如果后面是边界
                ll t=gra[x][y];
                if(t>1)  return 0;//因为后面是边界,且箱子数比1多
                gra[x][y]=0;
                if(dfs(x,y,cnt-1,s,0,0))  return 1;
                gra[x][y]=1;//回溯
            }
            else{//如果后面不是边界
                ll t=gra[x][y];
                gra[x][y]=0;
                gra[x+dir[d][0]][y+dir[d][1]]+=t-1;
                if(dfs(x,y,cnt-1,s,0,0))  return 1;
                gra[x][y]=t;//回溯
                gra[x+dir[d][0]][y+dir[d][1]]+=1-t;
            }
        }
    }
    return 0;
}
int main(){
    while(scanf("%lld%lld",&c,&r)==2){
        ll cnt=0;
        char br[33];
        for(ll i=1;i<=r;i++){//预处理
            scanf("%s",br+1);//注意!!!这里别用getchar()一个个字符处理读入,很可能因为数据有多余空格出错!!!
            for(ll j=1;j<=c;j++){
                if(br[j]=='.')  gra[i][j]=0;
                else{
                    gra[i][j]=br[j]-'a'+1;
                }  
                cnt+=gra[i][j];
            }
        }
        string s;
        for(ll i=1;i<=r;i++){
            for(ll j=1;j<=c;j++){//枚举每个点作为起点
                if(gra[i][j]!=0)  continue;//起点不能有箱子
                if(dfs(i,j,cnt,s,0,0)){
                    cout<<i-1<<"\n";
                    cout<<j-1<<"\n";
                    cout<<outs<<"\n";
                    i=r+1;j=c+1;//双重循环可以这样子退出!!!
                }
            }
        }
    }
    return 0;
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

Marhoosh

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值