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
");
else pf("%d
",ans);
Init();
}
return 0;
}