POJ 3322 Bloxorz I(进阶指南,广搜)

算法竞赛进阶指南,112页, 广搜,坐标变换
题目意思:
4433 小游戏上面的 推木头游戏,http://www.4399.com/flash/13071.htm#search3

本题要点:
1、长方体的状态表示, (x, y, lie) 其中 x, y 表示坐标,lie 表示长方体怎样摆放
lie == 0, 长方体立起来,与地面接触只有 的一面是 1 * 1 的正方形
lie == 1, 长方体横向躺着,左半部分在 位置 (x, y)
lie == 2, 长方体竖向向躺着,左半部分在 位置 (x, y)
2、 状态的起点和终点
起点:长方体可能立起来(图形只有1个 ‘X’),可能横躺(图形只有2个 ‘X’), 可能竖躺着(图形只有2个 ‘X’)
终点:长方体只能立起来(图形只有1个 ‘X’)

3、关键的左边变换
next_x[i][j] 表示 lie = i 时朝方向j 滚动后x的变化情况
next_x[i][j] 表示 lie = i 时朝方向j 滚动后y的变化情况
next_x[i][j] 表示 lie = i 时朝方向j 滚动后lie的变化情况

4、 每一种状态 State, 进行有效性判断

#include 
#include 
#include 
#include 
using namespace std;
const int MaxN = 510;
struct State
{
     
	int x, y, lie;
};
queue<State> q;
State st, ed;	// 起点,终点状态
int n, m;
char s[MaxN][MaxN];
int dist[MaxN][MaxN][3];
const int dx[4] = {
     0, 0, -1, 1}, dy[4] = {
     -1, 1, 0, 0};//左右上下
const int next_x[3][4] = {
     {
     0, 0, -2, 1}, {
     0, 0, -1, 1}, {
     0, 0, -1, 2}};//next_x[i][j] 表示 lie = i 时朝方向j 滚动后x的变化情况
const int next_y[3][4] = {
     {
     -2, 1, 0, 0}, {
     -1, 2, 0, 0}, {
     -1, 1, 0, 0}};//next_x[i][j] 表示 lie = i 时朝方向j 滚动后y的变化情况
const int next_lie[3][4] = {
     {
     1, 1, 2, 2}, {
     0, 0, 1, 1}, {
     2, 2, 0, 0}};//next_x[i][j] 表示 lie = i 时朝方向j 滚动后lie的变化情况

bool judge_xy(int x, int y)
{
     
	return x >= 1 && x <= n && y >= 1 && y <= m;
}

bool judge(State next)	//注意有易碎地面
{
     
	if(!judge_xy(next.x, next.y))
		return false;
	if(s[next.x][next.y] == '#')
		return false;
	if(next.lie == 0 && s[next.x][next.y] != '.')
		return false;
	if(next.lie == 1 && s[next.x][next.y + 1] == '#')
		return false;
	if(next.lie == 2 && s[next.x + 1][next.y] == '#')
		return false;
	return true;
}

void parse_st_ed()	//处理起点和终点
{
     
	for(int i = 1; i <= n; ++i)
		for(int j = 1; j <= m; ++j)
		{
     
			if('O' == s[i][j])	//终点
			{
     
				ed.x = i, ed.y = j, ed.lie = 0;
				s[i][j] = '.';
			}else if('X' == s[i][j]){
     	//起点, 这里的 'X' 是第一个 
				int a, b, lie = 0;
				for(int k = 0; k < 4; ++k)
				{
     
					a = i + dx[k], b = j + dy[k];
					if(a >= 1 && a <= n && b >= 1 && b <= m && 'X' == s[a][b])//这里的 'X' 是第二个
					{
     
						if(k == 1)	
						{
     
							lie = 1;	
						}else if(k == 3){
     
							lie = 2;
						}
						s[a][b] = '.';
					}
				}
				st.x = i, st.y = j, st.lie = lie, s[i][j] = '.';
			}
		}
}

int bfs()
{
     
	while(q.size())
	{
     
		q.pop();
	}
	memset(dist, -1, sizeof(dist));
	State s, next;
	q.push(st);
	dist[st.x][st.y][st.lie] =0;
	while(q.size())
	{
     
		s = q.front();
		q.pop();
		for(int j = 0; j < 4; ++j)
		{
     
			int i = s.lie;
			next.x = next_x[i][j] + s.x;
			next.y = next_y[i][j] + s.y;
			next.lie = next_lie[i][j];
			if(judge(next) && -1 == dist[next.x][next.y][next.lie])
			{
     
				dist[next.x][next.y][next.lie] = dist[s.x][s.y][s.lie] + 1;	
				q.push(next);
				if(next.x == ed.x && next.y == ed.y && next.lie == ed.lie)
				{
     
					return dist[next.x][next.y][next.lie];
				}
			}
		}
	}
	return -1;
}

int main()
{
     
	while(scanf("%d%d", &n, &m) != EOF && n)
	{
     
		for(int i = 1; i <= n; ++i)
		{
     
			scanf("%s", s[i] + 1);
		}
		parse_st_ed();
		int ans = bfs();
		if(-1 == ans)
		{
     
			printf("Impossible\n");
		}else{
     
			printf("%d\n", ans);
		}
	}
	return 0;
}

/*
7 7
#######
#..X###
#..##O#
#....E#
#....E#
#.....#
#######
0 0
*/

/*
10
*/

你可能感兴趣的:(算法竞赛进阶指南,搜索,POJ)