【分治法】棋盘覆盖问题 C/C++(附代码和测试实例及算法分析)

问题描述

在一个 2 k × 2 k 2^k \times 2^k 2k×2k大小的棋盘中,有一个与其他方块不同的特殊方块,如下图红色方块。另有4种形态不同的L型骨块(见下图),要用图示四种骨块覆盖棋盘上除特殊方格外的其他所有方格,且任何两个L型骨块不得重叠。
棋盘
在这里插入图片描述

问题分析

对于一个大棋盘,可将其横竖分成等大的四个子棋盘,每个棋盘大小为 2 k × 2 k 2^k\times2^k 2k×2k,分成四个子问题,减小问题规模。但这四个子棋盘中只有一个子棋盘有特殊方块的存在,四个子问题不相同,不符合分治法的要求。

为了使子问题满足分治法的条件,可以在大棋盘中央覆盖一个L型骨块(见下图),将该骨块视为特殊方块,这样每个子棋盘中都有一个特殊方块,四个子问题相同,可以使用分治法解决。

在这里插入图片描述

递归的将大棋盘分成子棋盘,直到分割成1x1的方块,此时该子棋盘有且仅有一个被覆盖好的特殊方块,就不需要再做处理了

这样,这个问题就解决了

代码思路

函数声明:

void chessBoard(int tr, int tc, int dr, int dc, int size);

参数解释:

  1. tr (top row):

    • 意义:当前子棋盘的左上角所在的行号。
    • 作用:用于确定当前子棋盘在整个棋盘中的位置。递归调用时,tr 会随着子棋盘的分割而变化。
  2. tc (top column):

    • 意义:当前子棋盘的左上角所在的列号。
    • 作用:与 tr 类似,用于确定当前子棋盘在整个棋盘中的位置。递归调用时,tc 也会随着子棋盘的分割而变化。
  3. dr (defect row):

    • 意义:特殊方格所在的行号。
    • 作用:用于确定特殊方格在当前子棋盘中的位置。递归调用时,dr 会与当前子棋盘的边界进行比较,以确定特殊方格是否在当前子棋盘中。
  4. dc (defect column):

    • 意义:特殊方格所在的列号。
    • 作用:与 dr 类似,用于确定特殊方格在当前子棋盘中的位置。递归调用时,dc 会与当前子棋盘的边界进行比较,以确定特殊方格是否在当前子棋盘中。
  5. size:

    • 意义:当前子棋盘的大小(边长)。
    • 作用:用于确定当前子棋盘的尺寸。每次递归调用时,size 会减半,直到 size 为 1 时递归终止。

函数体

在函数中,size=1为递归边界,size不为1时,将当前的骨块标号tile赋给变量t,同时tile自增1。并将分割后的子棋盘大小size/2赋给变量s。

二维数组board用于存储覆盖该位置的骨牌标号。

函数主体由四部分组成,每一部分分别覆盖左上角、右上角、左下角、右下角子棋盘

以左上角为例:

  • 如果特殊方格在此棋盘中,递归调用自身,继续覆盖当前子棋盘的左上角子棋盘
  • 如果特殊方格不在此棋盘中,用t号骨牌覆盖其右下角,并将其作为特殊方块,递归调用自身,覆盖其余方块

代码如下:

	//覆盖左上角子棋盘
	if (dr < tr + s && dc < tc + s)//特殊方格在此棋盘中
		chessBoard(tr, tc, dr, dc, s);
	else {	//特殊方格不在此棋盘中
		board[tr + s - 1][tc + s - 1] = t;//用t号骨牌覆盖右下角
		chessBoard(tr, tc, tr + s - 1, tc + s - 1, s);//覆盖其余方格
	}

重复上述过程,对左上角、右上角、左下角、右下角子棋盘均进行覆盖

递归过程:

  • 基本情况:当 size == 1 时,递归终止,因为此时棋盘已经无法再分割。
  • 递归情况
    • 将当前棋盘分成四个大小相等的子棋盘。
    • 检查特殊方格是否在某个子棋盘中:
      • 如果在,则递归处理该子棋盘。
      • 如果不在,则在该子棋盘的适当位置放置一个L型骨牌,并递归处理该子棋盘。

示例:

假设有一个 8x8 的棋盘,特殊方格位于 (3, 4),初始调用为 chessBoard(0, 0, 3, 4, 8)

  1. 第一次调用

    • tr = 0, tc = 0, dr = 3, dc = 4, size = 8
    • 将棋盘分成四个 4x4 的子棋盘。
    • 检查特殊方格 (3, 4) 是否在左上角子棋盘 (0,0) 到 (3,3) 中。不在,因此在右下角放置一个L型骨牌,并递归处理左上角子棋盘。
  2. 递归调用

    • 对于左上角子棋盘,调用 chessBoard(0, 0, 3, 3, 4)
    • 继续分割和递归,直到 size == 1

通过这种方式,函数会递归地覆盖整个棋盘,确保每个子棋盘都被正确覆盖,最终完成棋盘覆盖问题的解决。

实例代码

对一个 8x8 的棋盘,特殊方格位于 (3, 4),对其标记-1,进行覆盖,并输出覆盖后的棋盘

#include<stdio.h>
#define MAX_SIZE 8
int tile = 1;
int board[MAX_SIZE][MAX_SIZE];
void chessBoard(int tr, int tc, int dr, int dc, int size) {
	if (size == 1)
		return;
	int t = tile++;//L型骨牌号
	int s = size / 2;//分割棋盘
	//覆盖左上角子棋盘
	if (dr < tr + s && dc < tc + s)//特殊方格在此棋盘中
		chessBoard(tr, tc, dr, dc, s);
	else {	//特殊方格不在此棋盘中
		board[tr + s - 1][tc + s - 1] = t;//用t号骨牌覆盖右下角
		chessBoard(tr, tc, tr + s - 1, tc + s - 1, s);//覆盖其余方格
	}
	//覆盖右上角子棋盘
	if (dr < tr + s && dc >= tc + s)//特殊方格在此棋盘中
		chessBoard(tr, tc + s, dr, dc, s);
	else {	//特殊方格不在此棋盘中
		board[tr + s - 1][tc + s] = t;//用t号骨牌覆盖右下角
		chessBoard(tr, tc + s, tr + s - 1, tc + s, s);//覆盖其余方格
	}
	//覆盖左下角子棋盘
	if (dr >= tr + s && dc < tc + s)//特殊方格在此棋盘中
		chessBoard(tr + s, tc, dr, dc, s);
	else {	//特殊方格不在此棋盘中
		board[tr + s][tc + s - 1] = t;//用t号骨牌覆盖右下角
		chessBoard(tr + s, tc, tr + s, tc + s - 1, s);//覆盖其余方格
	}
	//覆盖右下角子棋盘
	if (dr >= tr + s && dc >= tc + s)//特殊方格在此棋盘中
		chessBoard(tr + s, tc + s, dr, dc, s);
	else {	//特殊方格不在此棋盘中
		board[tr + s][tc + s] = t;//用t号骨牌覆盖右下角
		chessBoard(tr + s, tc + s, tr + s, tc + s, s);//覆盖其余方格
	}
}
int main() {
	int size = MAX_SIZE;
	int dr = 3, dc = 4;
	board[dr][dc] = -1; // 特殊方格
	chessBoard(0, 0, dr, dc, size);
	for (int i = 0; i < size; i++)
	{
		for (int j = 0; j < size; j++) {
			printf("%2d ", board[i][j]);
		}
		printf("\n");
	}
	return 0;
}

运行结果

在这里插入图片描述
可以看出,除标记为-1的位置(特殊方块)为覆盖外,其他的方格均被相应标号的骨块覆盖

为了计算棋盘覆盖算法的时间复杂度,我们可以分析递归调用的次数以及每次递归调用的工作量。

算法分析:

  1. 递归关系

    • 每次递归调用将棋盘分成四个大小相等的子棋盘。
    • 每次递归调用处理一个大小为 n 2 × n 2 \frac{n}{2} \times \frac{n}{2} 2n×2n 的子棋盘。
    • 递归终止条件是当棋盘大小为 1 x 1 时。
  2. 递归树

    • 每次递归调用会产生四个子问题,每个子问题的规模是原问题的一半。
    • 递归树的深度为 log ⁡ 2 n \log_2 n log2n 因为每次递归调用将问题规模减半。
  3. 工作量

    • 每次递归调用的工作量是常数时间 O(1) ,因为主要操作是检查特殊方格的位置和放置L型骨牌。

时间复杂度计算:

  1. 递归调用次数

    • 每次递归调用会产生四个子问题,因此递归调用的总次数为 4 l o g 2 n 4^{log_2 n} 4log2n
    • 由于 4 log ⁡ 2 n = ( 2 2 ) log ⁡ 2 n = 2 2 log ⁡ 2 n = n 2 4^{\log_2 n} = (2^2)^{\log_2 n} = 2^{2 \log_2 n} = n^2 4log2n=(22)log2n=22log2n=n2所以递归调用的总次数为 O(n^2) 。
  2. 每次递归调用的工作量

    • 每次递归调用的工作量是常数时间 O(1) 。
  3. 总时间复杂度

    • 总时间复杂度为递归调用次数乘以每次递归调用的工作量,即 O ( n 2 ) × O ( 1 ) = O ( n 2 ) O(n^2) \times O(1) = O(n^2) O(n2)×O(1)=O(n2)

详细计算过程:

  1. 递归关系式

    • 设 T(n) 为处理大小为 n x n 的棋盘的时间复杂度。
    • 递归关系式为:
      T ( n ) = 4 T ( n 2 ) + O ( 1 ) T(n) = 4T\left(\frac{n}{2}\right) + O(1) T(n)=4T(2n)+O(1)
  2. 展开递归关系式

    • 展开递归关系式:
      T ( n ) = 4 T ( n 2 ) + O ( 1 ) T(n) = 4T\left(\frac{n}{2}\right) + O(1) T(n)=4T(2n)+O(1)
      T ( n 2 ) = 4 T ( n 4 ) + O ( 1 ) T\left(\frac{n}{2}\right) = 4T\left(\frac{n}{4}\right) + O(1) T(2n)=4T(4n)+O(1)
      T ( n 4 ) = 4 T ( n 8 ) + O ( 1 ) T\left(\frac{n}{4}\right) = 4T\left(\frac{n}{8}\right) + O(1) T(4n)=4T(8n)+O(1)
      ⋮ \vdots
      T ( 1 ) = O ( 1 ) T(1) = O(1) T(1)=O(1)
  3. 求和

    • 将递归关系式展开后,总时间复杂度为:
      T ( n ) = 4 log ⁡ 2 n × O ( 1 ) = n 2 × O ( 1 ) = O ( n 2 ) T(n) = 4^{\log_2 n} \times O(1) = n^2 \times O(1) = O(n^2) T(n)=4log2n×O(1)=n2×O(1)=O(n2)

综上,棋盘覆盖算法的时间复杂度为 O ( n 2 ) O(n^2) O(n2),其中 n 是棋盘的边长。这是因为每次递归调用将问题规模减半,但每次递归调用会产生四个子问题,最终递归调用的总次数为 O ( n 2 ) O(n^2) O(n2)

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

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

el-table的hasChildren不生效?子级没数据还显示箭头号?树形数据无法展开和收缩

问题&#xff1a;明明子级只有一条数据&#xff0c;还显示箭头号 原因&#xff1a;最开始row-key写的是id,父级和子级都有该属性&#xff0c;所以展开失效了。 解决方法&#xff1a;row-key&#xff1a;id改成 row-key"name"

2002-2019年各省人口老龄化程度数据

2002-2019年各省人口老龄化程度数据 1、时间&#xff1a;2002-2019年 2、来源&#xff1a;国家统计局、统计年鉴 3、指标&#xff1a;地区、年度、六十五岁以上占比 4、范围&#xff1a;31省 5、指标解释&#xff1a;人口老龄化是指人口生育率降低和人均寿命延长导致的总人…

面向机器学习的Java库与平台简介、适用场景、官方网站、社区网址

Java机器学习的库与平台 最近听到有的人说要做机器学习就一定要学Python&#xff0c;我想他们掌握的知道还不够系统全面。本文作者给大家介绍几种常用Java实现的机器学习库&#xff0c;快快收藏加关注吧&#xff5e; Java机器学习库表格 Java机器学习库整理库/平台概念适合场…

MySQL 之服务器配置和状态(MySQL Server Configuration and Status)

MySQL 之服务器配置和状态 1 MySQL 架构和性能优化 1.3 服务器配置和状态 设置 MySQL 服务的特性&#xff0c;可以通过 mysqld 服务选项&#xff0c;服务器系统变量和服务器状态变量这三个方面来进行设置和查看。 官方文档 https://dev.mysql.com/doc/refman/8.0/en/serve…

Linux的基础指令和环境部署,项目部署实战(下)

目录 上一篇&#xff1a;Linxu的基础指令和环境部署&#xff0c;项目部署实战&#xff08;上&#xff09;-CSDN博客 1. 搭建Java部署环境 1.1 apt apt常用命令 列出所有的软件包 更新软件包数据库 安装软件包 移除软件包 1.2 JDK 1.2.1. 更新 1.2.2. 安装openjdk&am…

LabVIEW无刷电机控制器检测系统

开发了一种基于LabVIEW的无刷电机控制器检测系统。由于无刷电机具有高效率、低能耗等优点&#xff0c;在电动领域有取代传统电机的趋势&#xff0c;而无刷电机的核心部件无刷电机控制器产量也在不断增长。然而&#xff0c;无刷电机控制器的出厂检测仍处于半自动化状态&#xff…

《仙台有树》里的馅料(序)

《仙台有树》一起追剧吧&#xff08;二&#xff09;&#xff1a;馅料合集概览 ●德爱武美玩&#xff0c;全面发展 ●猜猜我是谁&真假美清歌 ●失忆的风还是吹到了仙台 ●霸道师徒强制收&你拜我&#xff0c;我拜你&#xff0c;师徒徒师甜蜜蜜 ●霸道总裁强制爱 ●仙台有…

网站搭建基本流程

需求分析&#xff1a; 实现网站搭建的过程&#xff1a;首先进行网站的需求性分析 网站可分为前台系统和后台系统&#xff0c;由不同的功能拆分为不同的模块 如下是一个电商网站可以拆分出的模块&#xff1a; 在编写代码前&#xff0c;我们要先对网站进行架构&#xff0c;通过…

反射机制的简单示例

一个使用反射机制的简单示例&#xff0c;这个示例将展示如何使用反射来实现一个通用的数据导出功能。 首先&#xff0c;让我们创建必要的项目结构和文件&#xff1a; 首先修改 pom.xml 添加依赖&#xff1a; <?xml version"1.0" encoding"UTF-8"?&…

Qt:多元素控件

目录 多元素控件介绍 QListWidget QTableWidget QTreeWidget 多元素控件介绍 多元素控件表示这个控件中包含了很多的元素&#xff0c;元素可能指的是字符串&#xff0c;也可以指的是更加复杂的数据结构、图片等等 Qt 中提供的多元素控件有: QListWidgetQListViewQTableW…

DeepSeek 助力 Vue 开发:打造丝滑的范围选择器(Range Picker)

前言&#xff1a;哈喽&#xff0c;大家好&#xff0c;今天给大家分享一篇文章&#xff01;并提供具体代码帮助大家深入理解&#xff0c;彻底掌握&#xff01;创作不易&#xff0c;如果能帮助到大家或者给大家一些灵感和启发&#xff0c;欢迎收藏关注哦 &#x1f495; 目录 Deep…

STL —— 洛谷字符串(string库)入门题(蓝桥杯题目训练)(一)

目录 一、B2109 统计数字字符个数 - 洛谷 算法代码&#xff1a; 1. 引入库和命名空间 2. 主函数 3. 读取输入 4. 变量初始化 5. 遍历字符串 6. 输出结果 7. 返回值 总结 评测记录&#xff1a; 二、B2110 找第一个只出现一次的字符 - 洛谷 方法一&#xff1a;算法代…

Golang GORM系列:GORM并发与连接池

GORM 是一个流行的 Go 语言 ORM&#xff08;对象关系映射&#xff09;库&#xff0c;用于简化数据库操作。它支持连接池和并发访问功能&#xff0c;这些功能对于高性能、高并发的应用场景非常重要。本文结合示例详细介绍gorm的并发处理能力&#xff0c;以及如何是哟个连接池提升…

C#之上位机开发---------C#通信库及WPF的简单实践

〇、上位机&#xff0c;分层架构 界面层 要实现的功能&#xff1a; 展示数据 获取数据 发送数据 数据层 要实现的功能&#xff1a; 转换数据 打包数据 存取数据 通信层 要实现的功能&#xff1a; 打开连接 关闭连接 读取数据 写入数据 实体类 作用&#xff1a; 封装数据…

Ubuntu24安装MongoDB(解压版)

目录 0.需求说明1.环境检查2.下载软件2.1.下载MongoDB服务端2.2.下载MongoDB连接工具(可略过)2.3.检查上传或下载的安装包 3.安装MongoDB3.1.编辑系统服务3.2.启动服务3.3.客户端连接验证3.3.1.创建管理员用户 4.远程访问4.1.开启远程访问4.2.开放防火墙 0.需求说明 问&#x…

《DeepSeek-V3:人工智能大语言模型》

《DeepSeek-V3:人工智能大语言模型》 1. 引言 我们介绍了 DeepSeek-V3,这是一个强大的专家混合 (MoE) 语言模型,总共有 671B 个参数,每个令牌激活了 37B。 为了实现高效的推理和具有成本效益的训练,DeepSeek-V3 采用了多头潜在注意力 (MLA) 和 DeepSeekMoE 架构,这些…

解锁机器学习核心算法 | K -近邻算法:机器学习的神奇钥匙

一、引言 今天我们继续学习机器学习核心算法 —— K - 近邻&#xff08;K-Nearest Neighbors&#xff0c;简称 KNN&#xff09;算法。它就像是一位经验丰富的 “老江湖”&#xff0c;以其简单而又强大的方式&#xff0c;在众多机器学习任务中占据着不可或缺的地位。 K - 近邻…

算法分析—— 《归并排序》

《排序数组》 题目描述&#xff1a; 给你一个整数数组 nums&#xff0c;请你将该数组升序排列。 你必须在 不使用任何内置函数 的情况下解决问题&#xff0c;时间复杂度为 O(nlog(n))&#xff0c;并且空间复杂度尽可能小。 示例 1&#xff1a; 输入&#xff1a;nums [5,2…

linux云服务器部署deepseek,并通过网页访问

参考视频&#xff1a;https://www.douyin.com/root/search/linux%E5%AE%89%E8%A3%85%20deepseek?aid3aa2527c-e4f2-4059-b724-ab81a140fa8b&modal_id7468518885570940214&typegeneral 修改ollama配置文件 vim /etc/systemd/system/ollama.service 我的电脑硬盘只有4…

FastAdmin后端列表导入表格数据

后台添加数据的时候增加通过表格导入功能 如下图index.html页面增加导入和模板下载按钮代码如下 <div class"panel panel-default panel-intro">{:build_heading()}<div class"panel-body"><div id"myTabContent" class"ta…