(HDU2821)Pusher-DFS

Pusher

Time Limit: 2000/1000 MS (Java/Others)    Memory Limit: 32768/65536 K (Java/Others)
Total Submission(s): 1811    Accepted Submission(s): 674
Special Judge

 

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.

 

 

Input

There are several test cases in each input. The first two lines of each case contain two numbers C and R. (R,C <= 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.)
 

 

 

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 <= x < R, 0 <= y < C). The third line contains a moving sequence contains 'U', 'D', 'L' and 'R'. Any correct answer will be accepted.

 

 

Sample Input

 

3 7 ... ... .b. ... ... .a. ...

 

 

Sample Output

 

4 1 UDU

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.

题目分析:

题目大意就是推杆推物体,地图变空就结束,输出推杆推的过程中的走向。当推杆和物体紧挨着时,物体不被推动,当被推物体的相邻的后面还有物体时,两物体合在一起,当后面相邻的没有物体时,当前的物体减一。推杆可以向四个方向去搜,但一旦选定一个方向就会一直走下去,直到推不动物体,或出界,就换方向。

当时一直不知道怎么判断推杆能否推当前物体,看了别人的后发现,可以先在当前方向上走一步,这样问题就可以简化,即推杆和物体紧挨着时是可以推动的情况(原来是必须隔一个位置)。枚举的时候,枚举每个物体周围距离为2的位置。

代码:

#include<iostream>
#include<string.h>
using namespace std;
int R, C;
char maze[27][27];
int a[27][27];
int p_select[4][2] = { {2,0}, {-2,0}, {0,-2}, {0,2} };
int p[4][2] = { {1,0}, {-1,0}, {0,1}, {0,-1} };
int num = 0,cnt = 0;
char path[1000];
char dir[] = "DURL";
int ok(int x, int y) {
	if (x < 0 || y < 0 || x >= R || y >= C)//出界
		return 0;
	if (a[x][y] == 0)//空地
		return 1;
	return -1;	//有物体
}

int dfs(int x, int y,int pos) {
	int xx, yy,tx,ty;
	for (int i = 0; i < 4; i++)
	{
		//先走一步
		xx = x + p[i][0];
		yy = y + p[i][1];
		if (ok(xx, yy) != 1)continue; //如果走一步之后没出界并且可以走(说明该方向上相邻位置上的没有物体,那么后面再遇到物体后你就可以推了)
		//继续向当前方向走,直到出界或遇到物体
		do
		{
			xx += p[i][0];
			yy += p[i][1];
		} while (ok(xx, yy) == 1);
		//如果当前位置有物体并且物体后面没出界(可能有物体也可能没有)
		if (ok(xx, yy) && ok(tx = xx + p[i][0], ty = yy + p[i][1]))
		{
			int t = a[xx][yy];
			path[pos] = dir[i];
			if (t == 1 || a[tx][ty]) {
				cnt--;
			}
			if (cnt == 0)
			{
				num = pos;
				return 1;
			}
			a[tx][ty] += t - 1;
			a[xx][yy] = 0;
			if (dfs(xx, yy, pos + 1))return 1;
			a[xx][yy] = t;
			a[tx][ty] -= t - 1;
			if (t == 1 || a[tx][ty])cnt++;
		}
	}
	return 0;
}

int main() {
	while (cin >> C >> R)
	{
		num = 0;
		int flag = 1;
		int vis[27][27];
		memset(vis, 0, sizeof(vis));
		int x, y;
		for (int i = 0; i < R; i++)
		{
			for (int j = 0; j < C; j++)
			{
				cin >> maze[i][j];
				if (maze[i][j] >= 'a'&&maze[i][j] <= 'z')
				{
					a[i][j] = maze[i][j] - 'a' + 1;
					num++;//记有多少个物体
				}
				else
					a[i][j] = 0;
			}
		}

		//枚举每个物体周围距离为2的点进行深搜
		for (int i = 0; i < R&&flag; i++)
		{
			for (int j = 0; j < C&&flag; j++)
			{
				if (a[i][j]) 
				{
					for (int k = 0; k < 4&&flag; k++)
					{
						x = i + p_select[k][0];
						y = j + p_select[k][1];
						if (ok(x,y)>0&&!vis[x][y])
						{
							vis[x][y] = 1;
							cnt = num;
							if (dfs(x, y, 0))flag = 0;
						}
					}
				}
			}
		}
		cout << x << endl << y << endl;
		for (int i = 0; i <= num; i++)cout << path[i];
		cout<<endl;
	}
	return 0;
}

 

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值