NOIP2011提高组day1 - T3:Mayan游戏(玛雅游戏)

news2024/11/18 2:55:16

题目链接

[NOIP2011 提高组] Mayan 游戏

题目描述

Mayan puzzle 是最近流行起来的一个游戏。游戏界面是一个 7 7 7 × 5 \times5 ×5 列的棋盘,上面堆放着一些方块,方块不能悬空堆放,即方块必须放在最下面一行,或者放在其他方块之上。游戏通关是指在规定的步数内消除所有的方块,消除方块的规则如下:

  1. 每步移动可以且仅可以沿横向(即向左或向右)拖动某一方块一格:当拖动这一方块时,如果拖动后到达的位置(以下称目标位置)也有方块,那么这两个方块将交换位置(参见输入输出样例说明中的图 6 6 6 到图 7 7 7);如果目标位置上没有方块,那么被拖动的方块将从原来的竖列中抽出,并从目标位置上掉落(直到不悬空,参见下面图 1 1 1 和图 2 2 2);

  1. 任一时刻,如果在一横行或者竖列上有连续三个或者三个以上相同颜色的方块,则它们将立即被消除(参见图1 到图3)。

注意:

a) 如果同时有多组方块满足消除条件,几组方块会同时被消除(例如下面图 4 4 4,三个颜色为 1 1 1 的方块和三个颜色为 2 2 2 的方块会同时被消除,最后剩下一个颜色为 2 2 2 的方块)。

b) 当出现行和列都满足消除条件且行列共享某个方块时,行和列上满足消除条件的所有方块会被同时消除(例如下面图5 所示的情形, 5 5 5 个方块会同时被消除)。

  1. 方块消除之后,消除位置之上的方块将掉落,掉落后可能会引起新的方块消除。注意:掉落的过程中将不会有方块的消除。

上面图 1 1 1 到图 3 3 3 给出了在棋盘上移动一块方块之后棋盘的变化。棋盘的左下角方块的坐标为 ( 0 , 0 ) (0,0) (0,0),将位于 ( 3 , 3 ) (3,3) (3,3) 的方块向左移动之后,游戏界面从图 1 1 1 变成图 2 2 2 所示的状态,此时在一竖列上有连续三块颜色为 4 4 4 的方块,满足消除条件,消除连续 3 3 3 块颜色为 4 4 4 的方块后,上方的颜色为 3 3 3 的方块掉落,形成图 3 3 3 所示的局面。

输入格式

6 6 6 行。

第一行为一个正整数 n n n,表示要求游戏通关的步数。

接下来的 5 5 5 行,描述 7 × 5 7 \times 5 7×5 的游戏界面。每行若干个整数,每两个整数之间用一个空格隔开,每行以一个 0 0 0 结束,自下向上表示每竖列方块的颜色编号(颜色不多于 10 10 10 种,从 1 1 1 开始顺序编号,相同数字表示相同颜色)。

输入数据保证初始棋盘中没有可以消除的方块。

输出格式

如果有解决方案,输出 n n n 行,每行包含 3 3 3 个整数 x , y , g x,y,g x,y,g,表示一次移动,每两个整数之间用一个空格隔开,其中 ( x , y ) (x,y) (x,y) 表示要移动的方块的坐标, g g g 表示移动的方向, 1 1 1 表示向右移动, − 1 -1 1 表示向左移动。注意:多组解时,按照 x x x 为第一关键字, y y y 为第二关键字, 1 1 1 优先于 − 1 -1 1,给出一组字典序最小的解。游戏界面左下角的坐标为 ( 0 , 0 ) (0,0) (0,0)

如果没有解决方案,输出一行 -1

样例 #1

样例输入 #1

3
1 0
2 1 0
2 3 4 0
3 1 0
2 4 3 4 0

样例输出 #1

2 1 1
3 1 1
3 0 1

提示

【输入输出样例说明】

按箭头方向的顺序分别为图 6 6 6 到图 11 11 11

样例输入的游戏局面如上面第一个图片所示,依次移动的三步是: ( 2 , 1 ) (2,1) (2,1) 处的方格向右移动, ( 3 , 1 ) (3,1) (3,1) 处的方格向右移动, ( 3 , 0 ) (3,0) (3,0) 处的方格向右移动,最后可以将棋盘上所有方块消除。

【数据范围】

对于 30 % 30\% 30% 的数据,初始棋盘上的方块都在棋盘的最下面一行;

对于 100 % 100\% 100% 的数据, 0 < n ≤ 5 0<n \le 5 0<n5

算法思想

根据题目描述,可以分析出下面一些有用的信息。

  • 方块的移动规则:
    • 每步移动可以且仅可以沿横向(即向左或向右)拖动某一方块一格
    • 当拖动这一方块时,如果拖动后到达的位置也有方块,那么这两个方块将交换位置
    • 如果目标位置上没有方块,那么被拖动的方块将从原来的竖列中抽出,并从目标位置上掉落,直到不悬空
  • 方块的消除规则:
    • 如果在一横行或者竖列上有连续三个或者三个以上相同颜色的方块,则它们将立即被消除
    • 如果同时有多组方块满足消除条件,几组方块会同时被消除
    • 如果行和列都满足消除条件且行列共享某个方块时,行和列上满足消除条件的所有方块会被同时消除
  • 方块消除之后,消除位置之上的方块将掉落,掉落后可能会引起新的方块消除

由于题目给出的数据范围比较小,游戏通关的步数 n ≤ 5 n \le 5 n5,也就是最多枚举 5 5 5步得到解决方案,因此直接暴力搜索每一步移动的方块,模拟移动和消除的过程即可。

搜索顺序

依次枚举每一步选择哪个方块,向左右哪个方向移动。

可行性剪枝

当某种颜色的方块数量小于等于 2 2 2时,无法消除,则一定无解,直接剪枝。

优化性剪枝

根据输出要求,多组解时,按照 x x x 为第一关键字, y y y 为第二关键字, 1 1 1 优先于 − 1 -1 1,给出一组字典序最小的解。其中 1 1 1表示向右移动, − 1 -1 1表示向左移动。

如果将有颜色的方块 ( i , j ) (i,j) (i,j)向左移动时,而左侧方块 ( i − 1 , j ) (i-1, j) (i1,j)也有颜色,则不如将左边的方块向右移动,即 ( i − 1 , j ) → ( i , j ) (i-1, j)\to(i, j) (i1,j)(i,j),这样得到的字典序更小。因此在这种情况下,应该进行最优性剪枝。

移动和消除

当选择将 a a a b b b行的方块移动 c c c b b b行时,即 ( a , b ) → ( c , b ) (a, b)\to(c, b) (a,b)(c,b)

  • 首先将这两个方块将交换位置
  • 其次要重复下面几个步骤,直到没有方块被消除为止:
    • 处理悬空方块,即被移走或者消除的方块上面的方块要落下来。
    • 检查行列上是否有符合消除规则的方块,将其标记为消除
    • 消除方块

时间复杂度

总共有 5 × 7 = 35 5\times7=35 5×7=35个方块,每个格子可以向左或向右移动,一共移动 5 5 5步,也就是说最坏情况下每一步都有 70 70 70种选择,时间复杂度为 O ( 7 0 5 ) O(70^5) O(705)

但随着方块被消除,以及剪枝操作,实际搜索的空间远小于最坏情况。

代码实现

#include <iostream>
#include <cstring>
using namespace std;
struct S {
    int x, y, d; //记录移动过程
}ans[5];
int n;
int g[5][7], bg[5][5][7]; //bg备份数组,用于回溯恢复现场
int cnt[15], bcnt[5][15]; //cnt[i]表示第i种颜色的方块数量
bool st[5][7]; //用来标记方块是否被消除
void move(int a, int b, int c)
{
    swap(g[a][b], g[c][b]); //交换两个方块
    while(true) //一直处理直到没有消除方块
    {
        for(int i = 0; i < 5; i ++) //处理悬空方块
        {
            int k = 0;
            for(int j = 0; j < 7; j ++) //有颜色的方块向下移动
                if(g[i][j]) g[i][k ++] = g[i][j];
            while(k < 7) g[i][k ++] = 0; //将k上方的方块都设置为0
        }
        
        memset(st, 0, sizeof st);
        bool flag = false; //是否消除了方块
        //消除方块
        for(int i = 0; i < 5; i ++)
            for(int j = 0; j < 7; j ++)
            {
                if(g[i][j])
                {
                    int L = i, R = i; //计算方块(i,j)左右相同颜色方块的数量
                    while(L - 1 >= 0 && g[L - 1][j] == g[i][j]) L --;
                    while(R + 1 < 5 && g[R + 1][j] == g[i][j]) R ++;
                    if(R - L + 1 >= 3) //可以消除
                    {
                        st[i][j] = true; //标记成消除状态
                        flag = true;
                    }
                    else //不能消除则继续检查同一列是否能消除
                    {
                        int D = j, U = j; //计算方块(i,j)上下相同颜色方块的数量
                        while(D - 1 >= 0 && g[i][D - 1] == g[i][j]) D --;
                        while(U + 1 < 7 && g[i][U + 1] == g[i][j]) U ++; //注意这里小于7行
                        if(U - D + 1 >= 3)
                        {
                            st[i][j] = true;
                            flag = true;
                        }
                    }
                    
                }
            }
        if(!flag) break;
        for(int i = 0; i < 5; i ++)
            for(int j = 0; j < 7; j ++)
                if(st[i][j]) //消除格子
                {
                    cnt[0] --;
                    cnt[g[i][j]] --;
                    g[i][j] = 0;
                }
    }
}

bool dfs(int u)
{
    if(u == n) return cnt[0] == 0; //搜索结束,如果方块全部消除则有解
    
    for(int i = 1; i <= 10; i ++) //可行性剪枝,当某种颜色的方块数量小于等于2时,无法消除,则一定无解
        if(cnt[i] == 1 || cnt[i] == 2)
            return false;
    
    memcpy(bg[u], g, sizeof g); //备份,用来恢复现场
    memcpy(bcnt[u], cnt, sizeof cnt); 
    //选择1个方块进行移动
    for(int i = 0; i < 5; i ++)
        for(int j = 0; j < 7; j ++)
            if(g[i][j]) //有方块
            {
                int c = i + 1; //向右移动
                if(c < 5)
                {
                    ans[u] = {i, j, 1};
                    move(i, j, c);
                    if(dfs(u + 1)) return true;
                    memcpy(g, bg[u], sizeof g); //回溯,恢复现场
                    memcpy(cnt, bcnt[u], sizeof cnt);
                }
                c = i - 1; //向左移动
                if(c >= 0 && g[c][j] == 0) //向左移动,而左边方块也有颜色,进行最优性剪枝
                {
                    ans[u] = {i, j, -1};
                    move(i, j, c);
                    if(dfs(u + 1)) return true;
                    memcpy(g, bg[u], sizeof g); //回溯,恢复现场
                    memcpy(cnt, bcnt[u], sizeof cnt);
                }
            }
    return false;
}
int main()
{
    scanf("%d", &n);
    for(int i = 0; i < 5; i ++) //枚举列
    {
        int c, j = 0; //j表示行
        while(scanf("%d", &c), c != 0)
        {
            g[i][j ++] = c;
            cnt[0] ++; //方块的总数
            cnt[c] ++; //c颜色的方块数量
        }
    }
    if(dfs(0)) //从第0步暴力搜索
    {
        for(int i = 0; i < n; i ++)
            printf("%d %d %d\n", ans[i].x, ans[i].y, ans[i].d);
    }
    else puts("-1");
    return 0;
}

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/1396542.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

bug笔记:解决 HTTP Error 500.30 - ASP.NET Core app failed to start

总结下后端部署windos iis环境net6版本&#xff0c;500.30问题报错的一种解决方案&#xff1a; 一、问题描述 二、解决方案 检查下是否安装了net6对应的环境&#xff0c;是否已经安装 然后在事件管理器>Windows日志>应用程序&#xff0c;里面查看详细异常记录 在iis下面…

机器学习平台建设(六)

四、OpenPAI 前文介绍了机器学习平台的功能以及建设机器学习平台要考虑的因素。本节会介绍OpenPAI&#xff0c;即微软的开源机器学习平台。它可用于企业私有部署&#xff0c;也可部署在云平台中。它解决了建模训练时的算力和资源管理的问题。OpenPAI的开发很活跃&#xff0c;问…

工业设备管理系统:助力企业实现数字化转型

随着工业4.0和智能制造的快速发展&#xff0c;数字化转型已成为企业提升竞争力、适应市场变化的必然选择。工业设备管理系统作为数字化转型的关键组成部分&#xff0c;能够为企业提供实时监控、数据分析、预警和远程控制等功能&#xff0c;助力企业实现数字化转型的目标。 一、…

【办公类-21-02】20240118育婴员操作题word打印2.0

作品展示 把12页一套的操作题批量制作10份&#xff0c;便于打印 背景需求 将昨天整理的育婴师操作题共享&#xff0c; 因为题目里面有大量的红蓝颜色文字&#xff0c;中大班办公室都是黑白单面手动翻页打印。只有我待的教务室办公室有彩色打印机打印&#xff08;可以自动双面…

【GPU调用及CUDA安装 看完全会!】使用gpu进行各类训练/运行代码

检查 是否有GPU 打开任务管理器&#xff0c;我这边显示有gpu 查看有没有安装cuda nvidia-smi我没有CUDA 安装CUDA https://developer.nvidia.com/cuda-toolkit-archive 选择自定义安装 不要勾选Visual Studio 记录下面安装目录&#xff0c;如果后续环境变量没有自动…

Docker(五)访问仓库

作者主页&#xff1a; 正函数的个人主页 文章收录专栏&#xff1a; Docker 欢迎大家点赞 &#x1f44d; 收藏 ⭐ 加关注哦&#xff01; 访问仓库 仓库&#xff08;Repository&#xff09;是集中存放镜像的地方。 一个容易混淆的概念是注册服务器&#xff08;Registry&#xf…

Linux下使用Docker部署MinIO实现远程上传

&#x1f4d1;前言 本文主要是Linux下通过Docker部署MinIO存储服务实现远程上传的文章&#xff0c;如果有什么需要改进的地方还请大佬指出⛺️ &#x1f3ac;作者简介&#xff1a;大家好&#xff0c;我是青衿&#x1f947; ☁️博客首页&#xff1a;CSDN主页放风讲故事 &#…

【Docker】在Windows操作系统上安装Docker

欢迎来到《小5讲堂》&#xff0c;大家好&#xff0c;我是全栈小5。 这是《Docker容器》序列文章&#xff0c;每篇文章将以博主理解的角度展开讲解&#xff0c; 特别是针对知识点的概念进行叙说&#xff0c;大部分文章将会对这些概念进行实际例子验证&#xff0c;以此达到加深对…

2024-01-15(SpringMVCMybatis)

1.拦截器&#xff1a;如果我们想在多个handler方法(controller中的方法)执行之前或者之后都进行一些处理&#xff0c;甚至某些情况下需要拦截掉&#xff0c;不让handler方法执行&#xff0c;那么就可以使用SpringMVC为我们提供的拦截器。 拦截器和过滤器的区别&#xff1a;过滤…

java使用jsch处理软链接判断是否文件夹

前言 这一次主要是碰到一个问题。因为使用jsch去读取文件的时候&#xff0c;有一些文件它是使用软链接制作的一个映射。因为这里面有一个问题。如果它是软链接你就无法判断他到底是文件。还是文件夹&#xff1f;因为他没有提供可以直接读取的方法&#xff0c;用权限信息去判断…

Freemarker的基本语法及入门基础

freemarker的基本语法及入门基础 一、freemarker模板文件(*.ftl)的基本组成部分 1. 文本&#xff1a;直接输出的内容部分 2. 注释&#xff1a;不会输出的内容&#xff0c;格式为<#-- 注释内容 --> 3. 取值(插值)&#xff1a;代替输出数据模型的…

基于Spring+mybatis+vue的饮食分享系统(Java毕业设计)

大家好&#xff0c;我是DeBug&#xff0c;很高兴你能来阅读&#xff01;作为一名热爱编程的程序员&#xff0c;我希望通过这些教学笔记与大家分享我的编程经验和知识。在这里&#xff0c;我将会结合实际项目经验&#xff0c;分享编程技巧、最佳实践以及解决问题的方法。无论你是…

INS-06003错误处理

在麒麟V10操作系统上安装Oracle RAC 19C&#xff0c;安装GI的建立互信步骤中&#xff0c;遇到INS-06003错误&#xff1a; [INS-06003] Failed to setup password SSH connectivity with following node(s) 查看详细信息&#xff1a; PRVG-11001: PRCZ-2136: PRCZ-2006: 此时在操…

C++ 设计模式之 中介者模式

【声明】本题目来源于卡码网&#xff08;题目页面 (kamacoder.com)&#xff09; 【提示&#xff1a;如果不想看文字介绍&#xff0c;可以直接跳转到C编码部分】 【设计模式大纲】 【简介】 -- 什么是中介者模式 &#xff08;第16种模式&#xff09; 中介者模式&#xff08;Medi…

C#控制台相关

CSharp控制台相关 在进行控制台小游戏开发时&#xff0c;常用到的控制台命令代码。 知识点一&#xff1a;输入、输出 重点&#xff1a; char c Console.ReadKey(true).KeyChar; 作用&#xff1a;可以不显示输入的这个字符&#xff0c;并且用c 记录该按键输入的数据。 知…

DC-3靶机刷题记录

靶机下载地址&#xff1a; 链接&#xff1a;https://pan.baidu.com/s/1-P5ezyt5hUbmmGMP4EI7kw?pwdrt2c 提取码&#xff1a;rt2c 参考&#xff1a; http://t.csdnimg.cn/hhPi8https://www.vulnhub.com/entry/dc-32,312/ 官网http://t.csdnimg.cn/5mVZ7DC-3 (1).pdfhttps://…

JAVAEE初阶 网络原理初识

网络原理 一.局域网1.1 局域网组件网络的几种关系 二. 广域网三. 网络通信基础概念3.1 IP3.2 端口3.3 协议3.4 拆分3.5 拆分的优点 四. TCP/IP五层模型4.1 网络设备的分层 一.局域网 局域网是 Local Area Network 简称 LAN。 局域网是本地&#xff0c;局部私自建立的一种网络。…

CSV文件中json列的处理2

如上所示&#xff0c;csv文件中包含以中括号{}包含的json字段&#xff0c;可用如下方法提取&#xff1a; import pandas as pd from datetime import date todaystr(date.today()) import jsonfilepath/Users/kangyongqing/Documents/kangyq/202401/调课功能使用统计/ file104…

开发语音产品时设计唤醒词和命令词的技巧

在实际开发语音产品过程中&#xff0c;要达到好的语音识别效果&#xff0c;除了语音算法要给力外&#xff0c;设计出好的唤醒词和命令词也能起到事倍功半的效果。所以下面介绍一下如何设计中文、英文和日文的唤醒词和命令词。 中文唤醒词设计 一般为4-6个字&#xff0c;4个字最…

天眼销会员系统上线:低至9.9/月!

天眼销是一款提供企业线索的产品&#xff0c;致力于帮助客户获取最新的企业联系方式、工商信息等关键数据。 此前天眼销的收费模式是按条数收费&#xff0c;每条0.07叠加充值优惠&#xff0c;最优惠也要差不多0.05/条。 现在新的会员系统上线了&#xff0c;比以往更加优惠&am…