NOIP2011提高组.玛雅游戏

news2025/4/18 16:30:56

目录

题目

185. 玛雅游戏
在这里插入图片描述

算法标签: 模拟, 搜索, d f s dfs dfs, 剪枝优化

思路

可行性剪枝

  • 如果某个颜色的格子数量少于 3 3 3一定无解
  • 因为要求字典序最小, 因此当一个格子左边有格子, 不能向左移动, 应该向右移动, 具体来说当前位置向左移动 ( x , y , − 1 ) (x, y, -1) (x,y,1), 但是左边格子向右移动 ( x − 1 , y , 1 ) (x - 1, y, 1) (x1,y,1), 字典序是更小的
    因为每个格子整体上向右移动

时间复杂度 3 5 5 35 ^ 5 355大概 5 × 1 0 7 5 \times 10 ^ 7 5×107

*详细注释版代码

#include <cstring>
#include <iostream>
#include <algorithm>

using namespace std;

const int R = 7, C = 5, S = 5;
const int TYPE = 11;

int n; // 需要通关的步数
int g[C][R]; // 游戏棋盘,5列7行(x:0-4, y:0-6)
int bg[S][C][R]; // 备份棋盘状态,用于回溯,bg[step][x][y]表示第step步时的棋盘状态
int cnt[TYPE]; // 统计每种颜色方块的数量,cnt[0]是所有方块总数,cnt[1-10]是各颜色方块数
int bcnt[S][TYPE]; // 备份方块数量统计,用于回溯
bool st[C][R]; // 标记哪些方块需要被消除

struct Path {
	int x, y, d; // 记录移动路径:x,y是坐标,d是方向(1右,-1左)
} path[5]; // 存储每一步的移动

// 移动方块并处理消除和掉落
void move(int a, int b, int c) {
	// 交换两个方块
	swap(g[a][b], g[c][b]);

	while (true) {
		bool flag = true; // 标记是否还有可以消除的方块

		// 处理悬空方块,让方块下落
		for (int x = 0; x < 5; x++) {
			int z = 0;
			// 压缩非空方块到列底部
			for (int y = 0; y < 7; y++)
				if (g[x][y])
					g[x][z++] = g[x][y];
			// 上方补0
			while (z < 7) g[x][z++] = 0;
		}

		// 检查可以消除的方块
		memset(st, 0, sizeof st);
		for (int x = 0; x < 5; x++)
			for (int y = 0; y < 7; y++)
				if (g[x][y]) {
					// 检查水平方向是否有3个或以上连续相同方块
					int l = x, r = x;
					while (l - 1 >= 0 && g[l - 1][y] == g[x][y]) l--;
					while (r + 1 < 5 && g[r + 1][y] == g[x][y]) r++;
					if (r - l + 1 >= 3) {
						st[x][y] = true;
						flag = false;
					}
					else {
						// 检查垂直方向是否有3个或以上连续相同方块
						l = r = y;
						while (l - 1 >= 0 && g[x][l - 1] == g[x][y]) l--;
						while (r + 1 < 7 && g[x][r + 1] == g[x][y]) r++;

						if (r - l + 1 >= 3) {
							st[x][y] = true;
							flag = false;
						}
					}
				}

		// 如果没有可以消除的方块,退出循环
		if (flag) break;

		// 消除标记的方块
		for (int x = 0; x < 5; x++)
			for (int y = 0; y < 7; y++)
				if (st[x][y]) {
					cnt[0]--; // 总数减1
					cnt[g[x][y]]--; // 对应颜色方块数减1
					g[x][y] = 0; // 清空该位置
				}
	}
}

// 深度优先搜索解决玛雅难题
bool dfs(int u) {
	// 如果达到目标步数且所有方块都被消除,返回成功
	if (u == n) return !cnt[0];

	// 剪枝:如果有颜色只剩1或2个方块,不可能消除完,提前返回
	for (int i = 1; i <= 10; i++)
		if (cnt[i] == 1 || cnt[i] == 2)
			return false;

	// 备份当前状态
	memcpy(bg[u], g, sizeof g);
	memcpy(bcnt[u], cnt, sizeof cnt);

	// 枚举所有可能的移动
	for (int x = 0; x < 5; x++)
		for (int y = 0; y < 7; y++)
			if (g[x][y]) {
				// 尝试向右移动
				int nx = x + 1;
				if (nx < 5) {
					path[u] = {x, y, 1}; // 记录路径
					move(x, y, nx); // 执行移动
					if (dfs(u + 1)) return true; // 递归搜索
					// 回溯
					memcpy(g, bg[u], sizeof g);
					memcpy(cnt, bcnt[u], sizeof cnt);
				}

				// 尝试向左移动
				nx = x - 1;
				if (nx >= 0 && !g[nx][y]) { // 左边为空才能移动(否则会与向右移动重复)
					path[u] = {x, y, -1}; // 记录路径
					move(x, y, nx); // 执行移动
					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 x = 0; x < 5; x++) {
		int t, y = 0;
		while (scanf("%d", &t), t) {
			cnt[0]++; // 总数增加
			cnt[t]++; // 对应颜色方块数增加
			g[x][y++] = t; // 放置方块
		}
	}

	// 深度优先搜索
	if (dfs(0)) {
		// 输出解决方案
		for (int i = 0; i < n; i++)
			printf("%d %d %d\n", path[i].x, path[i].y, path[i].d);
	}
	else {
		// 无解
		puts("-1");
	}

	return 0;
}

精简注释版代码

#include <iostream>
#include <algorithm>
#include <cstring>
#include <vector>

using namespace std;

const int R = 7, C = 5, S = 5;
const int TYPE = 11;

int n;
int g[C][R], bg[S][C][R];
int cnt[TYPE], bcnt[S][TYPE];
bool vis[C][R];

struct Path {
	int x, y, d;
} path[S];

// 处理方块移动和消除
void move(int a, int b, int na) {
	swap(g[a][b], g[na][b]);

	while (true) {
		bool flag = true;

		// 处理悬空方块,让它们下落
		for (int x = 0; x < C; ++x) {
			int z = 0;
			// 压缩非空方块到列底部
			for (int y = 0; y < R; ++y) {
				if (g[x][y]) {
					g[x][z++] = g[x][y];
				}
			}
			// 填充剩余位置为空
			while (z < R) {
				g[x][z++] = 0;
			}
		}

		memset(vis, false, sizeof vis);

		for (int x = 0; x < C; ++x) {
			for (int y = 0; y < R; ++y) {
				if (g[x][y]) {
					// 检查横向
					int l = x, r = x;
					while (l - 1 >= 0 && g[l - 1][y] == g[x][y]) l--;
					while (r + 1 < C && g[r + 1][y] == g[x][y]) r++;
					if (r - l + 1 >= 3) {
						vis[x][y] = true;
						flag = false;
					}
						// 检查纵向
					else {
						int u = y, d = y;
						while (u - 1 >= 0 && g[x][u - 1] == g[x][y]) u--;
						while (d + 1 < R && g[x][d + 1] == g[x][y]) d++;
						if (d - u + 1 >= 3) {
							vis[x][y] = true;
							flag = false;
						}
					}
				}
			}
		}

		if (flag) break;

		// 消除标记的方块
		for (int x = 0; x < C; ++x) {
			for (int y = 0; y < R; ++y) {
				if (vis[x][y]) {
					cnt[0]--;
					cnt[g[x][y]]--;
					g[x][y] = 0;
				}
			}
		}
	}
}

bool dfs(int u) {
	if (u == n) return !cnt[0];

	for (int i = 1; i <= 10; ++i) {
		if (cnt[i] == 1 || cnt[i] == 2) return false;
	}

	// 备份当前状态
	memcpy(bg[u], g, sizeof g);
	memcpy(bcnt[u], cnt, sizeof cnt);

	// 尝试所有可能的移动
	for (int x = 0; x < C; ++x) {
		for (int y = 0; y < R; ++y) {
			if (g[x][y]) {
				// 向右移动
				if (x + 1 < C) {
					path[u] = {x, y, 1};
					move(x, y, x + 1);
					if (dfs(u + 1)) return true;
					memcpy(g, bg[u], sizeof g);
					memcpy(cnt, bcnt[u], sizeof cnt);
				}

				// 向左移动
				if (x - 1 >= 0 && !g[x - 1][y]) {
					path[u] = {x, y, -1};
					move(x, y, x - 1);
					if (dfs(u + 1)) return true;
					memcpy(g, bg[u], sizeof g);
					memcpy(cnt, bcnt[u], sizeof cnt);
				}
			}
		}
	}

	return false;
}

int main() {
	ios_base::sync_with_stdio(false);
	cin.tie(0), cout.tie(0);

	cin >> n;

	for (int x = 0; x < C; ++x) {
		int t, y = 0;
		while (cin >> t, t) {
			cnt[0]++;
			cnt[t]++;
			g[x][y++] = t;
		}
	}

	if (dfs(0)) {
		for (int i = 0; i < n; ++i) {
			cout << path[i].x << " " << path[i].y << " " << path[i].d << "\n";
		}
	}
	else {
		cout << -1 << "\n";
	}

	return 0;
}

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

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

相关文章

基于ssm框架的校园代购服务订单管理系统【附源码】

1、系统框架 1.1、项目所用到技术&#xff1a; javaee项目 Spring&#xff0c;springMVC&#xff0c;mybatis&#xff0c;mvc&#xff0c;vue&#xff0c;maven项目。 1.2、项目用到的环境&#xff1a; 数据库 &#xff1a;mysql5.X、mysql8.X都可以jdk1.8tomcat8 及以上开发…

【10】数据结构的矩阵与广义表篇章

目录标题 二维以上矩阵矩阵存储方式行序优先存储列序优先存储 特殊矩阵对称矩阵稀疏矩阵三元组方式存储稀疏矩阵的实现三元组初始化稀疏矩阵的初始化稀疏矩阵的创建展示当前稀疏矩阵稀疏矩阵的转置 三元组稀疏矩阵的调试与总代码十字链表方式存储稀疏矩阵的实现十字链表数据标签…

猜猜乐游戏(python)

import randomprint(**30) print(欢迎进入娱乐城) print(**30)username input(输入用户名&#xff1a;) cs 0answer input( 是否加入"猜猜乐"游戏(yes/no)? )if answer yes:while True:num int(input(%s! 当前你的金币数为%d! 请充值(100&#xffe5;30币&…

spring boot 2.7 集成 Swagger 3.0 API文档工具

背景 Swagger 3.0 是 OpenAPI 规范体系下的重要版本&#xff0c;其前身是 Swagger 2.0。在 Swagger 2.0 之后&#xff0c;该规范正式更名为 OpenAPI 规范&#xff0c;并基于新的版本体系进行迭代&#xff0c;因此 Swagger 3.0 实际对应 OpenAPI 3.0 版本。这一版本着重强化了对…

Dinky 和 Flink CDC 在实时整库同步的探索之路

摘要&#xff1a;本文整理自 Dinky 社区负责人&#xff0c;Apache Flink CDC contributor 亓文凯老师在 Flink Forward Asia 2024 数据集成&#xff08;二&#xff09;专场中的分享。主要讲述 Dinky 的整库同步技术方案演变至 Flink CDC Yaml 作业的探索历程&#xff0c;并深入…

视频融合平台EasyCVR搭建智慧粮仓系统:为粮仓管理赋能新优势

一、项目背景 当前粮仓管理大多仍处于原始人力监管或初步信息化监管阶段。部分地区虽采用了简单的传感监测设备&#xff0c;仍需大量人力的配合&#xff0c;这不仅难以全面监控粮仓复杂的环境&#xff0c;还容易出现管理 “盲区”&#xff0c;无法实现精细化的管理。而一套先进…

3D Gaussian Splatting as MCMC 与gsplat中的应用实现

3D高斯泼溅(3D Gaussian splatting)自2023年提出以后,相关研究paper井喷式增长,尽管出现了许多改进版本,但依旧面临着诸多挑战,例如实现照片级真实感、应对高存储需求,而 “悬浮的高斯核” 问题就是其中之一。浮动高斯核通常由输入图像中的曝光或颜色不一致引发,也可能…

C++初阶-C++的讲解1

目录 1.缺省(sheng)参数 2.函数重载 3.引用 3.1引用的概念和定义 3.2引用的特性 3.3引用的使用 3.4const引用 3.5.指针和引用的关系 4.nullptr 5.总结 1.缺省(sheng)参数 &#xff08;1&#xff09;缺省参数是声明或定义是为函数的参数指定一个缺省值。在调用该函数是…

STM32_USB

概述 本文是使用HAL库的USB驱动 因为官方cubeMX生成的hal库做组合设备时过于繁琐 所以这里使用某大神的插件,可以集成在cubeMX里自动生成组合设备 有小bug会覆盖生成文件里自己写的内容,所以生成一次后注意保存 插件安装 下载地址 https://github.com/alambe94/I-CUBE-USBD-Com…

STM32 的编程方式总结

&#x1f9f1; 按照“是否可独立工作”来分&#xff1a; 库/方式是否可独立使用是否依赖其他库说明寄存器裸写✅ 是❌ 无完全自主控制&#xff0c;无库依赖标准库&#xff08;StdPeriph&#xff09;✅ 是❌ 只依赖 CMSIS自成体系&#xff08;F1专属&#xff09;&#xff0c;只…

MFC工具栏CToolBar从专家到小白

CToolBar m_wndTool; //创建控件 m_wndTool.CreateEx(this, TBSTYLE_FLAT|TBSTYLE_NOPREFIX, WS_CHILD | WS_VISIBLE | CBRS_FLYBY | CBRS_TOP | CBRS_SIZE_DYNAMIC); //加载工具栏资源 m_wndTool.LoadToolBar(IDR_TOOL_LOAD) //在.rc中定义&#xff1a;IDR_TOOL_LOAD BITMAP …

大厂机考——各算法与数据结构详解

目录及其索引 哈希双指针滑动窗口子串普通数组矩阵链表二叉树图论回溯二分查找栈堆贪心算法动态规划多维动态规划学科领域与联系总结​​ 哈希 ​​学科领域​​&#xff1a;计算机科学、密码学、数据结构 ​​定义​​&#xff1a;通过哈希函数将任意长度的输入映射为固定长度…

10:00开始面试,10:08就出来了,问的问题有点变态。。。

从小厂出来&#xff0c;没想到在另一家公司又寄了。 到这家公司开始上班&#xff0c;加班是每天必不可少的&#xff0c;看在钱给的比较多的份上&#xff0c;就不太计较了。没想到8月一纸通知&#xff0c;所有人不准加班&#xff0c;加班费不仅没有了&#xff0c;薪资还要降40%…

基于ueditor编辑器的功能开发之给编辑器图片增加水印功能

用户需求&#xff0c;双击编辑器中的图片的时候&#xff0c;出现弹框&#xff0c;用户可以选择水印缩放倍数、距离以及水印所放置的方位&#xff08;当然有很多水印插件&#xff0c;位置大小透明度用户都能够自定义&#xff0c;但是用户需求如此&#xff0c;就自己写了&#xf…

【CSS基础】- 02(emmet语法、复合选择器、显示模式、背景标签)

css第二天 一、emmet语法 1、简介 ​ Emmet语法的前身是Zen coding,它使用缩写,来提高html/css的编写速度, Vscode内部已经集成该语法。 ​ 快速生成HTML结构语法 ​ 快速生成CSS样式语法 2、快速生成HTML结构语法 生成标签 直接输入标签名 按tab键即可 比如 div 然后tab…

【码农日常】vscode编码clang-format格式化简易教程

文章目录 0 前言1 工具准备1.1 插件准备1.2 添加.clang-format1.3 添加配置 2 快速上手 0 前言 各路大神都说clangd好&#xff0c;我也来试试。这篇主要讲格式化部分。 1 工具准备 1.1 插件准备 照图安装。 1.2 添加.clang-format 右键添加文件&#xff0c;跟添加个.h或者.c…

金融数据分析(Python)个人学习笔记(7):网络数据采集以及FNN分类

一、网络数据采集 证券宝是一个免费、开源的证券数据平台&#xff08;无需注册&#xff09;&#xff0c;提供大盘准确、完整的证券历史行情数据、上市公司财务数据等&#xff0c;通过python API获取证券数据信息。 1. 安装并导入第三方依赖库 baostock 在命令提示符中运行&…

死锁 手撕死锁检测工具

目录 引言 一.理论联立 1.死锁的概念和原因 2.死锁检测的基本思路 3.有向图在死锁检测中的应用 二.代码实现案例&#xff08;我们会介绍部分重要接口解释&#xff09; 1.我们定义一个线性表来存线程ID和锁ID 2.表中数据的查询接口 3.表中数据的删除接口 4.表中数据的添…

软考高级-系统架构设计师 案例题-软件架构设计

文章目录 软件架构设计质量属性效用树&#xff0c;质量属性判断必背概念架构风格对比MVC架构J2EE四层结构面向服务架构SOA企业服务总线ESB历年真题【问题1】 &#xff08;12分)【问题2】&#xff08;13分&#xff09; 参考答案历年真题【问题1】&#xff08;12分&#xff09;【…

vue+d3js+fastapi实现天气柱状图折线图饼图

说明&#xff1a; vued3jsfastapi实现天气柱状图折线图饼图 效果图&#xff1a; step0:postman 1. 生成天气数据&#xff08;POST请求&#xff09;&#xff1a;URL: http://localhost:8000/generate-data/?year2024&month3&seed42 方法: POST Headers:Content-Type:…