UVALive 6888 Ricochet Robots bfs

本文介绍了一个涉及多个机器人的策略游戏,目标是通过最少的步骤将指定机器人移动到目标位置。机器人只能沿四个正交方向移动,并会在遇到障碍物时停止。文章提供了详细的解题思路和C++代码实现。

Ricochet Robots

题目连接:

http://acm.hust.edu.cn/vjudge/problem/visitOriginUrl.action?id=129726

Description

A team of up-to four robots is going to deliver parts in
a factory floor. The floor is organized as a rectangular
grid where each robot ocupies a single square cell.
Each robot is represented by an integer from 1 to 4
and can move in the four orthogonal directions (left,
right, up, down). However, once set in motion, a robot
will stop only when it detects a neighbouring obstacle
(i.e. walls, the edges of the factory or other stationary
robots). Robots do not move simultaneously, i.e. only
a single robot moves at each time step.
The goal is to compute an efficient move sequence
such that robot 1 reaches a designed target spot; this
may require moving other robots out of the way or to
use them as obstacles for “ricocheting” moves.
Consider the example given above, on the right,
where the gray cells represent walls, X is the target
location and ⃝1 , ⃝2 mark the initial positions of two robots. One optimal solution consists of the six
moves described below.
⃝2
⃝1
X
⃝1 moved up.
⃝1
⃝2 X
⃝2 moved right, down and left.
⃝2 ⃝1
⃝1 moved down and left.
Note that the move sequence must leave robot 1 at the target location and not simply pass through
it (the target does not cause robots to stop — only walls, edges and other robots).
Given the description of the factory floor plan, the initial robot and target positions, compute the
minimal total number of moves such that robot 1 reaches the target position.

Input

The input file contains several test cases, each of them as described below.
The first line contains the number of robots n, the width w and height h of the factory floor in cells,
and an upper-bound limit ℓ on the number of moves for searching solutions.
The remaining h lines of text represent rows of the factory floor with exactly w characteres each
representing a cell position:
‘W’ a cell occupied by a wall;
‘X’ the (single) target cell;
‘1’,‘2’,‘3’,‘4’ initial position of a robot;
‘.’ an empty cell.
Constraints:
1 ≤ n ≤ 4
max(w, h) ≤ 10
w, h ≥ 1
1 ≤ ℓ ≤ 10

Output

For each test case, the output should be the minimal number of moves for robot 1 to reach the target
location or ‘NO SOLUTION’ if no solution with less than or equal the given upper-bound number of moves
exists.

Sample Input

2 5 4 10
.2...
...W.
WWW..
.X.1.
1 5 4 10
.....
...W.
WWW..
.X.1.

Sample Output

6
NO SOLUTION

Hint

题意

给你一个棋盘,棋盘上面有最多四个棋子,你的目标是把一号棋子走到X位置,你可以动棋子,棋子的话,只能往四个方向走,走必须走到底,除非碰到边界或者墙,或者其他棋子。
让你在l步以内输出最小节,问你能不能。

题解:

一眼搜索题,但是究竟是dfs还是bfs呢?

他给你了个上界,所以一般就直接思考bfs了,而不是dfs

所以直接bfs莽一波就好了,没啥好说的呢,剩下就是码码码。

代码

#include <bits/stdc++.h>
#define rep(a,b,c) for(int (a)=(b);(a)<=(c);++(a))
#define drep(a,b,c) for(int (a)=(b);(a)>=(c);--(a))
#define pb push_back
#define mp make_pair
#define sf scanf
#define pf printf
#define two(x) (1<<(x))
#define clr(x,y) memset((x),(y),sizeof((x)))
#define dbg(x) cout << #x << "=" << x << endl;
#define input_fast std::ios::sync_with_stdio(false);std::cin.tie(0)
inline int read(){int x=0,f=1;char ch=getchar();while(ch<'0'||ch>'9'){if(ch=='-')f=-1;ch=getchar();}while(ch>='0'&&ch<='9'){x=x*10+ch-'0';ch=getchar();}return x*f;}
using namespace std;
const int maxn = 10 + 5;
const int mod = 100000;
int extra[8]={123,115,65147,233,6421,7361,73561,442};
int num,N,M,Limit,Up[maxn][maxn],Down[maxn][maxn],Lft[maxn][maxn],Rht[maxn][maxn],targetX,targetY;
char G[maxn][maxn];

bool inmap(int x , int y){ return 1 <= x && x <= N && 1 <= y && y <= M; }

int Got_Up(int x , int y){
    if(!inmap(x,y)||G[x][y]=='W') return 0;
    if(~Up[x][y]) return Up[x][y];
    return Up[x][y]=Got_Up(x-1,y)+1;
}

int Got_Down(int x , int y){
    if(!inmap(x,y)||G[x][y]=='W') return 0;
    if(~Down[x][y]) return Down[x][y];
    return Down[x][y]=Got_Down(x+1,y)+1;
}
int GOt_Lft(int x , int y){
    if(!inmap(x,y)||G[x][y]=='W') return 0;
    if(~Lft[x][y]) return Lft[x][y];
    return Lft[x][y]=GOt_Lft(x,y-1)+1;
}
int Got_Rht(int x , int y){
    if(!inmap(x,y)||G[x][y]=='W') return 0;
    if(~Rht[x][y]) return Rht[x][y];
    return Rht[x][y]=Got_Rht(x,y+1)+1;
}

struct Data{
    pair < int , int > p[4] ;
    int step ;

    int cal_hash(){
        int tot = 0  ;
        long long A = 0;
        rep(i,0,num-1){
            A += p[i].first * extra[tot ++ ];
            A += p[i].second * extra[tot ++ ];
        }
        if( A >= mod ) A %= mod;
        return (int)A;
    }

    Data( const pair < int , int > & a , const pair < int , int > & b , const pair < int , int > & c , const pair < int , int > & d , int sp ){ p[0]= a,p[1]=b,p[2]=c,p[3]=d,step=sp; }
};


vector < Data > Judge[mod];
pair < int , int > base[4];
queue < Data > Q;

void Try_Push( Data & np ){
    if(np.step > Limit) return ;
    int h = np.cal_hash();
    for(auto it : Judge[h] ){
        int ok = 1;
        rep(j,0,num - 1)
            if(it.p[j]!=np.p[j]){
                ok = 0 ;
                break;
            }
        if(ok) return ;
    }
    Q.push( np );
    Judge[h].pb(np);
}

void Init(){
    for(int i = 0 ; i < mod ; ++ i) Judge[i].clear();
}

int bfs(){
    while(!Q.empty()) Q.pop();
    Q.push( Data( base[0] , base[1] , base[2] , base[3] , 0 ));
    while(!Q.empty()){
        Data fq = Q.front() ; Q.pop();
        if( fq.p[0].first == targetX && fq.p[0].second == targetY ) return fq.step;
        if( fq.step == Limit ) continue;
        for(int idx = 0 ; idx <= num - 1 ; ++ idx ){
            // 准备移动第 idx 个
            pair < int , int > pos = fq.p[idx]; // 获得初始位置

            //cout << "Come here " << endl;

            int x  = pos.first , y = pos.second;
            // 向上
            {
                pair < int , int > nxtpos = mp( pos.first - Up[x][y] , pos.second );
                rep(j,0,num - 1){
                    if( fq.p[j].second == y && fq.p[j].first < pos.first && fq.p[j].first >= nxtpos.first  ){
                        nxtpos.first = fq.p[j].first + 1;
                    }
                }

                //cout << x << " " << y << " Up " << Up[x][y] << endl;
                //assert( inmap( nxtpos.first , nxtpos.second ));
                if(nxtpos.first != x){
                    Data newst = fq;
                    newst.p[idx] = nxtpos;
                    newst.step ++ ;
                    Try_Push( newst );
                }

            }

            // 向下
            {

                pair < int , int > nxtpos = mp( pos.first + Down[x][y] , pos.second );
                rep(j,0,num - 1){
                    if( fq.p[j].second == y && fq.p[j].first <= nxtpos.first && fq.p[j].first > pos.first  ){
                        nxtpos.first = fq.p[j].first - 1;
                    }
                }

                //              cout << x << " " << y << " Down " << Down[x][y] << endl;
                //assert( inmap( nxtpos.first , nxtpos.second ));
                if(nxtpos.first != x){
                    Data newst = fq;
                    newst.p[idx] = nxtpos;
                    newst.step ++ ;
                    Try_Push( newst );
                }

            }


            // 向左
            {
                pair < int , int > nxtpos = mp( pos.first , pos.second - Lft[x][y] );
                rep(j,0,num - 1){
                    if( fq.p[j].first == x && fq.p[j].second < pos.second && fq.p[j].second >= nxtpos.second  ){
                        nxtpos.second = fq.p[j].second + 1;
                    }
                }

                //              cout << x << " " << y << " Lft " << Lft[x][y] << endl;
                //assert( inmap( nxtpos.first , nxtpos.second ));
                if(nxtpos.second != y){
                    Data newst = fq;
                    newst.p[idx] = nxtpos;
                    newst.step ++ ;
                    Try_Push( newst );
                }

            }

            // 向右
            {

                pair < int , int > nxtpos = mp( pos.first , pos.second + Rht[x][y] );
                rep(j,0,num - 1){
                    if( fq.p[j].first == x && fq.p[j].second <= nxtpos.second && fq.p[j].second > pos.second  ){
                        nxtpos.second = fq.p[j].second - 1;
                    }
                }

                //              cout << x << " " << y << " Rht " << Rht[x][y] << endl;
                //assert( inmap( nxtpos.first , nxtpos.second ));
                if(nxtpos.second != y){
                    Data newst = fq;
                    newst.p[idx] = nxtpos;
                    newst.step ++ ;
                    Try_Push( newst );
                }
            }

        }
    }
    return -1;
}

int main(int argc,char *argv[]){
    while(~scanf("%d%d%d%d",&num,&M,&N,&Limit)){
        rep(i,1,N) sf("%s",G[i] + 1);
        clr(Lft,-1);clr(Up,-1);clr(Down,-1);clr(Rht,-1);
        rep(i,1,N) rep(j,1,M){
            GOt_Lft(i,j);Got_Up(i,j);Got_Down(i,j);Got_Rht(i,j);
        }
        rep(i,1,N)rep(j,1,M){
            Up[i][j]--;
            Down[i][j]--;
            Lft[i][j]--;
            Rht[i][j]--;
        }
        rep(i,1,N) rep(j,1,M){
            if(G[i][j]<='4'&&G[i][j]>='1'){
                int idx = G[i][j] - '1';
                base[idx] = mp( i , j );
            }else if(G[i][j]=='X'){
                targetX = i , targetY = j;
            }
        }
        int ans = bfs();
        if( ans == -1 ) pf("NO SOLUTION\n");
        else pf("%d\n",ans);
        Init();
    }
    return 0;
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值