• 【YBTOJ】立体推箱子


    题目大意:

    有一个 (N imes M) 的矩阵,每个位置可能是硬地(用 . 表示),易碎地面(用 E 表示),禁地(用 # 表示),起点(用 X 表示),终点(用 O 表示)。

    你的任务是操作一个 (1 imes1 imes2) 的长方体。

    这个长方体在地面上有两种放置方式,“立” 在地面上((1 imes1) 的面接触地面)或者 “躺” 在地面上((1 imes2) 的面接触地面)。

    在每一步操作中,可以按上下左右的四个键之一。

    按下按键之后,长方体向对应的方向沿着棱滚动 。

    任意时刻,长方体不能有任何部位接触禁地,并且不能立在易碎地面上。

    字符 X 标识长方体的起始位置,地图上可能有一个 X 或者两个相邻的 X

    地图上唯一的一个字符 O 标识目标位置。

    求把长方体移动到目标位置(即立在 O 上)所需要的最少步数。

    在移动过程中,X 和 O 的表示位置都可以看作是硬地被利用。

    (3leq n,Mleq500)

    正文:

    可以用三元组 ((id,x,y)) 来表示长方体:当 (id=1) 时,长方体立在地板;当 (id=2) 时,以 (1 imes2) 的面立在地板;当 (id=3) 时,以 (2 imes1) 的面立在地板。而 (x,y) 则表示长方体在地板上接触面的左上角。

    接着可以 BFS 了。

    代码:

    const int N = 510;
    
    /*
    1 *
    ----- 
    2 **
    ----- 
    3 *
      * 
    */
    struct point
    {
    	int id, x, y, stp;
    }s;
    int n, m;
    char a[N][N];
    bool vis[4][N][N];
    
    queue <point> q;
    
    bool ck(int x, int y) {return x > 0 && x <= n && y > 0 && y <= m && a[x][y] != '#';}
    
    void bfs()
    {
    	memset (vis, 0, sizeof vis);
    	while (!q.empty()) q.pop();
    	q.push(s);
    	while (!q.empty())
    	{
    		point u = q.front();q.pop();
    		if (vis[u.id][u.x][u.y]) continue;
    		else vis[u.id][u.x][u.y] = 1;
    		if (u.id == 1 && a[u.x][u.y] == 'O')
    		{
    			printf ("%d
    ", u.stp);
    			return;
    		}
    		if (u.id == 1)
    		{
    			if (ck(u.x, u.y - 1) && ck(u.x, u.y - 2))
    				q.push((point){2, u.x, u.y - 2, u.stp + 1});
    			if (ck(u.x, u.y + 1) && ck(u.x, u.y + 2))
    				q.push((point){2, u.x, u.y + 1, u.stp + 1});
    			if (ck(u.x - 1, u.y) && ck(u.x - 2, u.y))
    				q.push((point){3, u.x - 2, u.y, u.stp + 1});
    			if (ck(u.x + 1, u.y) && ck(u.x + 2, u.y))
    				q.push((point){3, u.x + 1, u.y, u.stp + 1});
    			continue;
    		}
    		if (u.id == 2)
    		{
    			if (ck(u.x, u.y - 1) && a[u.x][u.y - 1] != 'E')
    				q.push((point){1, u.x, u.y - 1, u.stp + 1});
    			if (ck(u.x, u.y + 2) && a[u.x][u.y + 2] != 'E')
    				q.push((point){1, u.x, u.y + 2, u.stp + 1});
    			if (ck(u.x - 1, u.y) && ck(u.x - 1, u.y + 1))
    				q.push((point){2, u.x - 1, u.y, u.stp + 1});
    			if (ck(u.x + 1, u.y) && ck(u.x + 1, u.y + 1))
    				q.push((point){2, u.x + 1, u.y, u.stp + 1});
    			continue;
    		}
    		if (u.id == 3)
    		{
    			if (ck(u.x, u.y - 1) && ck(u.x + 1, u.y - 1))
    				q.push((point){3, u.x, u.y - 1, u.stp + 1});
    			if (ck(u.x, u.y + 1) && ck(u.x + 1, u.y + 1))
    				q.push((point){3, u.x, u.y + 1, u.stp + 1});
    			if (ck(u.x - 1, u.y) && a[u.x - 1][u.y] != 'E')
    				q.push((point){1, u.x - 1, u.y, u.stp + 1});
    			if (ck(u.x + 2, u.y) && a[u.x + 2][u.y] != 'E')
    				q.push((point){1, u.x + 2, u.y, u.stp + 1});
    			continue;
    		}		
    	} 
    	printf ("Impossible
    ");
    }
    
    int main()
    {
    	for(scanf ("%d%d", &n, &m); n || m; scanf ("%d%d", &n, &m))
    	{
    		memset (a, 0, sizeof a);
    		s = (point){0, 0, 0, 0};
    		for (int i = 1; i <= n; i++)
    		{
    			scanf ("%s", a[i] + 1);
    			for (int j = 1; j <= m; j++)
    				if (a[i][j] == 'X')
    					if (s.id)
    					{
    						if (s.x - i) s.id = 3;
    						else s.id = 2;
    					}else
    						s.id = 1, s.x = i, s.y = j;
    		}
    		bfs();
    	}
    	return 0;
    }
    
  • 相关阅读:
    线程池的爆掉
    WebApi的调用-1.前端调用
    使用SqlSugar 4.X的T4生成实体类
    JSON.NET 空值处理, 数字转字符,时间格式化
    C#获取路径
    MVC4 下DropDownList使用方法(转)
    14.并发与异步
    14.并发与异步
    14.并发与异步
    VS2013 生成时复制文件或目录到指定目录
  • 原文地址:https://www.cnblogs.com/GJY-JURUO/p/14652782.html
Copyright © 2020-2023  润新知