HDU 2821 Pusher
\(\color{CornflowerBlue}{Problem\;Description}\)
PusherBoy is an online game http://www.hacker.org/push . There is an \(R * C\) grid, and there are piles of blocks on some positions. The goal is to clear the blocks by pushing into them.
You should choose an empty area as the initial position of the PusherBoy. Then you can choose which direction (\(U\) for up, \(D\) for down, \(L\) for left and \(R\) for right) to push. Once the direction is chosen, the PusherBoy will walk ahead until he met a pile of blocks (Walking outside the grid is invalid). Then he remove one block from the pile (so if the pile contains only one block, it will become empty), and push the remaining pile of blocks to the next area. (If there have been some blocks in the next area, the two piles will form a new big pile.)
Please note if the pusher is right up against the block, he can't remove and push it. That is, there must be a gap between the pusher and the pile. As the following figure, the pusher can go up, but cannot go down. (The cycle indicates the pusher, and the squares indicate the blocks. The nested squares indicate a pile of two blocks.)
And if a whole pile is pushed outside the grid, it will be considered as cleared.
\(\color{CornflowerBlue}{Input}\)
There are several test cases in each input. The first two lines of each case contain two numbers \(C\) and \(R\). \((R,C \leqslant 25)\) Then \(R\) lines follow, indicating the grid. '.' stands for an empty area, and a lowercase letter stands for a pile of blocks. ('a' for one block, 'b' for two blocks, 'c' for three, and so on.)
\(\color{CornflowerBlue}{Output}\)
Output three lines for each case. The first two lines contains two numbers \(x\) and \(y\), indicating the initial position of the PusherBoy.\((0 \leqslant x < R, 0 \leqslant y < C)\). The third line contains a moving sequence contains '\(U\)', '\(D\)', '\(L\)' and '\(R\)'. Any correct answer will be accepted.
\(\color{CornflowerBlue}{Sample\;Input}\)
3
7
...
...
.b.
...
...
.a.
...
\(\color{CornflowerBlue}{Sample\;Output}\)
4
1
UDU
\(\color{CornflowerBlue}{Hint}\)
Hint: The following figures show the sample. The circle is the position of the pusher.
And the squares are blocks (The two nested squares indicating a pile of two blocks). And this is the unique solution for this case.
\(\color{CornflowerBlue}{Source}\)
2009 Multi-University Training Contest 1 - Host by TJU
\(\color{CornflowerBlue}{Recommend}\)
gaojie | We have carefully selected several similar problems for you: 2822 2819 2820 2818 2824
题目描述
PusherBoy是一个在线游戏(http://www.hacker.org/push)。 有一个\(R * C\)的网格,在一些位置上有成堆的块。 目标是通过推动这些块来清除它们。
你应该选择一个空的区域作为PusherBoy的初始位置。 然后你可以选择哪个方向(\(U\)为向上,\(D\)为向下,\(L\)为左,\(R\)为右)来推动。 一旦选择了方向,PusherBoy就会一直走下去,直到他遇到一堆积木(走到网格外是无效的)。 然后他从堆中取出一个块(所以如果桩只包含一个块,它就会变成空的),并将剩余的一堆块推到下一个区域。 (如果在下一个区域有一些块,这两个堆将形成一个新的大堆。 )
请注意,如果pusher正好靠在块旁,他不能移除和推动它。 即pusher与堆之间一定有空隙。 如下图,推手可以上去,但不能下去。 (圆表示推子,方格表示块。 嵌套的正方形表示一堆两个块。 )
如果整个堆被推到网格外,它将被视为清除。
输入
输入文件包含若干组。 每组的前两行包含两个数字\(C\)和 \(R\) \((R,C \leqslant 25)\) 。接下来的\(R\)行,代表网格。 ‘.’ 代表一个空的区域,小写字母代表一堆块。 例如:a代表一个块的堆,b代表两个块的堆,c代表三个块的堆,等等。 )
输出
每组输出三行。 前两行包含两个数字\(x\)和\(y\),表示PusherBoy的初始位置。\((0 \leqslant x < R, 0 \leqslant y < C)\) .第三行代表移动序列包含 '\(U\)', '\(D\)', '\(L\)' 和 '\(R\)'。 任何正确的答案都将被接受。
提示
提示:下面的图解显示了样例。 圆圈是pusher的位置。
正方形是块(两个嵌套的正方形表示一堆两个块)。 这是这个样例的唯一解决方案。
Solution
思路借鉴于hexianhao的hdu 2821
1.理解题意,PusherBoy每撞到一个堆,就会清除堆中的一个块,并将堆往前推一个格;
2.通过分析,可以发现PusherBoy每次操作只能消除一个块(且必然消除一个块),所以答案的长度必然为块的总数;
3.由于题目范围不是很大,可以直接暴力枚举起点,让其尝试往四周走,按照题目条件寻找合法答案;
4.具体实现见代码
- TAG:搜索
std.cpp
#include<iostream>
#include<cstdio>
#include<cstring>
#include<algorithm>
using namespace std;
int R,C,tot,mp[30][30];
int fx[]={0,0,1,-1};
int fy[]={1,-1,0,0};
char ans[1005],m[30][30],d[]={'R','L','D','U'};
bool flag;
bool check(int x,int y){ return 0<=x&&x<R&&0<=y&&y<C; }
void dfs(int x,int y,int res){
if(res==tot){ flag=1; return; }
for(int i=0;i<4;++i){
if(flag) return;
//如果找到了一种答案,立即返回,否则之后的循环可能将答案更改
int nx=x+fx[i],ny=y+fy[i];
if(!check(nx,ny)||mp[nx][ny]) continue;
//如果出界或者此位置有堆,跳过
while(check(nx,ny)&&!mp[nx][ny]) nx+=fx[i],ny+=fy[i];
if(!check(nx+fx[i],ny+fy[i])) continue;
//一直朝一个方向走,直到撞到堆或者出界(出界即为非法)
int tmp=mp[nx][ny];
mp[nx+fx[i]][ny+fy[i]]+=tmp-1;
mp[nx][ny]=0;
ans[res]=d[i];
dfs(nx,ny,res+1);
mp[nx+fx[i]][ny+fy[i]]-=tmp-1;
mp[nx][ny]=tmp;
}
}
int main(){
while(scanf("%d %d",&C,&R)!=EOF){
tot=flag=0;
memset(ans,'\0',sizeof(ans));
for(int i=0;i<R;++i)
for(int j=0;j<C;++j){
cin>>m[i][j];
if(m[i][j]=='.') mp[i][j]=0;
else{
mp[i][j]=m[i][j]-'a'+1;
tot+=mp[i][j];
}
}
for(int i=0;i<R;++i){
if(flag) break;
for(int j=0;j<C;++j)
if(!mp[i][j]){
dfs(i,j,0);
if(flag){
printf("%d\n%d\n%s\n",i,j,ans);
break;
}
}
}
}
return 0;
}