《算法竞赛从入门到进阶》心得及相关题解009--dfs--hdu2821


题目意思:hdu2821,给定一张图,图上有些障碍物,将球放在没有障碍物的起始位置,球能上下左右移动,但不能滚出图外。移动时撞到障碍物可将障碍物的数量减一并推向下一位置,如果下一位置同样有障碍物则该位置障碍物数量可叠加。注意推动障碍物必须与障碍物至少有一个点的间隔,否则不能推动障碍物。求起始位置及移动的明细。
解题思路:模拟+dfs,注意障碍物可推出图外,因此可将数组稍微设大一点,可减少代码量及相关判断。
代码明细:
//probID: hdu2821
//author: WiselyQY
//date: 2020-12-29
#include <bits/stdc++.h>
using namespace std;

int g[30][30],m,n,ok,ansx,ansy;
string ans;
const int dx[]={1,0,-1,0}, dy[]={0,1,0,-1};
const char dir[]={'D','R','U','L'};
int allClear()
{
    for(int i=1; i<=m; i++)
        for(int j=1; j<=n; j++)
            if(g[i][j]) return 0;
    return 1;
}
int in(int x, int y)
{
    return x>=1 && x<=m && y>=1 && y<=n;
}
//从(x,y)位置出发,方向为k(0~3代表DRUL),返回0代表该方向不可行,返回1代表该方向可行,移动后新位置为(nx,ny)
int check(const int x, const int y, const int k, int& nx, int& ny)
{
    nx=x+dx[k]; ny=y+dy[k];
    if(in(nx,ny) && g[nx][ny]) return 0;
    nx+=dx[k]; ny+=dy[k];
    while(in(nx,ny) && !g[nx][ny]) {nx+=dx[k]; ny+=dy[k];}
    if(nx<1 || nx>m || ny<1 || ny>n) return 0;
    else
    {
        g[nx+dx[k]][ny+dy[k]]+=(g[nx][ny]-1);
        g[nx][ny]=0;
        return 1;
    }
}
void dfs(int x, int y)
{
    if(ok) return;
    if(allClear()) 
    {
        ok=1; 
        cout<<ansx-1<<endl<<ansy-1<<endl<<ans<<endl; 
        return;
    }
    int gn[30][30];
    string str;
    memcpy(gn,g,sizeof(g));
    str=ans;
    //DRUL四个方向分别尝试
    for(int i=0; i<4; i++)
    {
        int nx,ny;
        if(check(x,y,i,nx,ny))
        {
            ans+=dir[i];
            dfs(nx,ny);
            memcpy(g,gn,sizeof(gn));
            ans=str;
        }
    }
}
int main()
{
    clock_t start,end;
    start=clock();
#ifndef ONLINE_JUDGE
    freopen(R"(D:\code\hdu\2821\in.txt)","r",stdin);
#endif
    char ch[30][30];
    while(cin>>n>>m)
    {
        for(int i=1; i<=m; i++)
            for(int j=1; j<=n; j++) 
            {
                cin>>ch[i][j];
                if(ch[i][j]=='.') g[i][j]=0;
                else g[i][j]=ch[i][j]-'a'+1;
            }
        ans="";
        ok=0;
        int gn[30][30];
        memcpy(gn,g,sizeof(g));
        for(int i=1; i<=m; i++)
        {
            if(ok) break;
            ansx=i;
            for(int j=1; j<=n; j++)
            {
                if(ok) break;
                ansy=j;
                if(!g[i][j]) 
                {
                    dfs(i,j);
                    memcpy(g,gn,sizeof(gn));
                }
            }
        }
    }    
    end=clock();
    //printf("time=%lfs\n",(double)(end-start)/1000);
    return 0;
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值