用分治法求解棋盘覆盖问题
算法分析与设计教案
算法分析与设计课程教案课程编号:50c24037-01总学时:51 周学时:4适用年级专业(学科类):2007级计科专业开课时间:2010-2011 学年第1 学期使用教材:王晓东编著计算机算法设计与分析第3版章节第1章1.1~ 1.2 第2 章2.1 课时 2教学目的理解程序与算法的概念、区别与联系;掌握算法在最坏情况、最好情况和平均情况下的计算复杂性概念;掌握算法复杂性的渐近性态的数学表述;理解递归的概念。
教学重点及突出方法重点:程序与算法的概念、算法的时间复杂性、算法复杂性的渐近性态的数学表述以及递归的概念。
通过讲解、举例方法。
教学难点及突破方法难点:算法复杂性与递归通过讲解、举例、提问与引导方法。
相关内容此部分内容基础知识可参考清华大学出版社出版严蔚敏编著的《数据结构》教学过程(教师授课思路、设问及讲解要点)回顾数据结构课程中的算法概念、排序算法等知识,从而引出本课程内容。
提问算法与程序的区别、联系以及算法具有的特性。
讲解算法的复杂性,主要包括时间复杂性与空间复杂性。
讲解最坏情况、最好情况与平均情况的时间复杂性。
讲解算法复杂性在渐近意义下的阶,主要包括O、Ω、θ与o,并通过具体例子说明。
通过具体例子说明递归技术。
主要包括阶乘函数、Fibonacci数列、Ackerman函数、排列问题、整数划分问题、Hanoi塔问题等。
第页章节第2 章2.2~2.5 课时 2 教学目的掌握设计有效算法的分治策略,并掌握范例的设计技巧,掌握计算算法复杂性方法。
教学重点及突出方法重点:分治法的基本思想及分治法的一般设计模式。
通过讲解、举例方法。
教学难点及突破方法难点:计算算法复杂性。
通过讲解、举例、提问与引导方法。
相关内容素材教(教师授课思路、设问及讲解要点)学过程通过生活中解决复杂问题的分解方法,引出分治方法。
讲解分治法的基本思想及其一般算法的设计模式,介绍分治法的计算效率。
通过具体例子采用分治思想来设计有效算法。
如何应用分治算法求解问题
如何应用分治算法求解问题分治算法,英文名为Divide and Conquer Algorithm,是一种高效的算法设计策略,在计算机科学中有着广泛的应用。
该算法将一个大问题分解成多个小问题,各自独立地解决,再将结果合并起来得到最终结果。
在本文中,我们将阐述如何应用分治算法求解问题,并通过几个实例来具体说明该算法的应用。
一、分治算法的原理分治算法的核心思想是将一个大问题分解成若干个小问题来解决,然后将这些小问题的解组合起来生成大问题的解。
其具体步骤如下:1. 分解:将原问题划分成若干个规模较小的子问题。
2. 解决:递归地解决每个子问题。
如果子问题足够小,则直接求解。
3. 合并:将所有子问题的解合并成原问题的解。
分治算法的主要优点在于它可以有效地缩小问题规模,从而缩短整个算法的执行时间。
另外,该算法天然适用于并行计算,因为每个子问题都是独立求解的。
二、分治算法的应用分治算法在各种领域都有广泛应用,包括数学、自然科学、计算机科学等。
以计算机科学领域为例,分治算法常常用于解决以下类型的问题:1. 排序问题2. 查找问题3. 字符串匹配问题4. 最大子序列和问题5. 矩阵乘法问题6. 图形问题下面我们将一一讲解这些问题的分治算法实现。
1. 排序问题排序问题是在一组数据中将其按指定规律进行排列的问题。
在计算机科学中,排序算法是十分重要的一类算法。
其中,分治算法由于其高效性和可并行性被广泛应用。
常用的分治排序算法包括归并排序和快速排序。
归并排序的基本思想是将待排序元素以中心点为界分成两个序列,对每个序列进行排序,然后将两个序列合并成一个有序序列;而快速排序则利用了分割的思想,通过每次选取一个元素作为“轴点”,将数组分成小于轴点和大于轴点的两部分,对这两部分分别进行快速排序。
2. 查找问题查找问题是在一组数据中寻找某个元素的问题。
分治算法在查找问题中的应用主要体现在二分查找中。
在二分查找中,我们首先将已排序的数组分成两半,在其中一半中查找目标值。
分治算法-残缺棋盘
分治算法-残缺棋盘残缺棋盘是⼀个2^k*2^个⽅格的棋盘,其中恰有1个⽅格残缺。
图中给出,其中残缺部分⽤阴影表⽰。
这样的棋盘称为"三格板",残缺棋盘问题就是⽤这四种三格板覆盖更⼤的残缺棋盘。
再次覆盖中要求:(1)两个三格板不能重复。
(2)三格板不能覆盖残缺棋盘⽅格,但必须覆盖到其他所有的⽅格。
算法思路:利⽤分治算法将棋盘细化,逐步解决,以4*4为例⾸先判断残缺的位置在哪⾥,然后在中间填上对应的三格板,如在上图中间拼上三⾓板(4),变成下⾯这样然后通过中间将其分成了4个2*2的⼩残缺棋盘,从⽽问题得以解决4*4的分析过于简单,现在我们以8*8为例进⾏分析,能更清楚的理解这个例⼦中分治算法的思想⾸先将三格板放置在中间,将其分4个⼩的4*4的残缺棋盘通过红⾊线将其划分成4个4*4的残缺棋盘,现在以左上的残缺棋盘为例然后将左的4*4的⼩棋盘右划分成了4个2*2的⼩棋盘,这样就将问题优化成了2*2的三⾓棋盘的⼩问题,这样很快就能将左上的4*4的残缺棋盘解决了下⾯继续分析右上的4*4的棋盘,根据残缺的⽅格在⼩棋盘中的位置,在中间选择合适的三格板将⼩的残缺棋盘继续划分,将问题分化成更⼩的状态接着的问题和上⾯⼀样分析。
右上⾓的⼩棋盘很快也能解决了,下⾯两块残缺棋盘的分析⽅法和上⾯的⼀样,整个问题就这样⼀步步的分解成⼩问题,然后解决了。
下⾯是源代码#include <iostream>using namespace std;int amount,Board[100][100];void Cover(int tr,int tc,int dr,int dc,int size){int s,t;if(size<2)return ;amount++;t=amount;s=size/2;if(dr<tr+s&&dc<tc+s)//残缺在左上⾓{//覆盖中间位置Board[tr+s-1][tc+s]=t;Board[tr+s][tc+s-1]=t;Board[tr+s][tc+s]=t;Cover(tr,tc,dr,dc,s);//覆盖左上Cover(tr,tc+s,tr+s-1,tc+s,s);//覆盖右上Cover(tr+s,tc,tr+s,tc+s-1,s);//覆盖左下Cover(tr+s,tc+s,tr+s,tc+s,s);//覆盖右下}else if(dr<tr+s&&dc>=tc+s)//残缺在右上⾓{Board[tr+s-1][tc+s-1]=t;Board[tr+s][tc+s-1]=t;Board[tr+s][tc+s]=t;Cover(tr,tc,tr+s-1,tc+s-1,s);Cover(tr,tc+s,dr,dc,s);Cover(tr+s,tc,tr+s,tc+s-1,s);Cover(tr+s,tc+s,tr+s,tc+s,s);}else if(dr>=tr+s&&dc<tc+s)//残缺在左下 {Board[tr+s-1][tc+s-1]=t;Board[tr+s-1][tc+s]=t;Board[tr+s][tc+s]=t;Cover(tr,tc,tr+s-1,tc+s-1,s);Cover(tr,tc+s,tr+s-1,tc+s,s);Cover(tr+s,tc,dr,dc,s);Cover(tr+s,tc+s,tr+s,tc+s,s);}else{Board[tr+s-1][tc+s-1]=t;Board[tr+s-1][tc+s]=t;Board[tr+s][tc+s-1]=t;Cover(tr,tc,tr+s-1,tc+s-1,s);Cover(tr,tc+s,tr+s-1,tc+s,s);Cover(tr+s,tc,tr+s,tc+s-1,s);Cover(tr+s,tc+s,dr,dc,s);}}void Print(int s){for(int i=1;i<=s;i++){for(int j=1;j<=s;j++)printf("%5d ",Board[i][j]);printf("\n");}}int main(){int s=1,k,x,y;printf("输⼊2残缺棋盘的规模:2^k,k="); scanf("%d",&k);for(int i=1;i<=k;i++)s*=2;printf("输⼊棋盘残缺位置(x,y):");scanf("%d%d",&x,&y);Board[x][y]=0;Cover(1,1,x,y,s);Print(s);return 0;}。
算法设计与分析复习题目及答案 (3)
分治法1、二分搜索算法是利用(分治策略)实现的算法。
9. 实现循环赛日程表利用的算法是(分治策略)27、Strassen矩阵乘法是利用(分治策略)实现的算法。
34.实现合并排序利用的算法是(分治策略)。
实现大整数的乘法是利用的算法(分治策略)。
17.实现棋盘覆盖算法利用的算法是(分治法)。
29、使用分治法求解不需要满足的条件是(子问题必须是一样的)。
不可以使用分治法求解的是(0/1背包问题)。
动态规划下列不是动态规划算法基本步骤的是(构造最优解)下列是动态规划算法基本要素的是(子问题重叠性质)。
下列算法中通常以自底向上的方式求解最优解的是(动态规划法)备忘录方法是那种算法的变形。
(动态规划法)最长公共子序列算法利用的算法是(动态规划法)。
矩阵连乘问题的算法可由(动态规划算法B)设计实现。
实现最大子段和利用的算法是(动态规划法)。
贪心算法能解决的问题:单源最短路径问题,最小花费生成树问题,背包问题,活动安排问题,不能解决的问题:N皇后问题,0/1背包问题是贪心算法的基本要素的是(贪心选择性质和最优子结构性质)。
回溯法回溯法解旅行售货员问题时的解空间树是(排列树)。
剪枝函数是回溯法中为避免无效搜索采取的策略回溯法的效率不依赖于下列哪些因素(确定解空间的时间)分支限界法最大效益优先是(分支界限法)的一搜索方式。
分支限界法解最大团问题时,活结点表的组织形式是(最大堆)。
分支限界法解旅行售货员问题时,活结点表的组织形式是(最小堆)优先队列式分支限界法选取扩展结点的原则是(结点的优先级)在对问题的解空间树进行搜索的方法中,一个活结点最多有一次机会成为活结点的是( 分支限界法).从活结点表中选择下一个扩展结点的不同方式将导致不同的分支限界法,以下除( 栈式分支限界法)之外都是最常见的方式.(1)队列式(FIFO)分支限界法:按照队列先进先出(FIFO)原则选取下一个节点为扩展节点。
(2)优先队列式分支限界法:按照优先队列中规定的优先级选取优先级最高的节点成为当前扩展节点。
用Java实现L型骨牌覆盖问题的分治算法分析
象限
// 涂第 二象 限 i f ( dr <t r +s &&dc>=t c+s ){//特殊方块就在第二
Ch ess Boar d( t r ’t c+s ,d r ,dc,s) :
} el se {//第 二象限的 左下角 方块赋值 为t ( t i l e)
Boar d[ t r +s — 1] [ t c+s ] =t : // 涂第 二象 限其余 的方 块
( 下转第93页)
鼹■
应用 科学
关于x- ,x 2,xs的计算,程序中有具体的公式,而其它一些软约束条 件,也可通过各种方法得到实现,比如,要照顾岁数大的教师的问题,可 在数 据库 中排 序。 先排出 需要 照顾 的教师 的课 程, 然后 加一个 锁定 标记 , 这样 ,在 后边 的交 叉和变 异操 作中 ,这些 锁定 的点 也不 会被轻 易的 交换 , 保证了需要照 顾的特性。
2“×2卜l 2H×2“
2}l × 2缸l 2丘- l × 2丘_1
■
_■
l
图3 L型骨牌问题分治算法分析 设丁( 七) 为覆盖特殊棋盘的时间,当七=0时覆盖它需要常数时间 0( 1) .当 七>0时,测试 哪个子棋盘特殊 以及形成3个特殊子棋 盘需要 时『日J 0( 1) ,覆盖4个残缺子棋盘需四次递归调用,共需4 丁( 七一1) ,所以
一源代码privatevoichessboardintntdrntdcfsize1ntssize特殊方块就在第一象限chessboarcdrdcselse特殊方块不在第一象限第一象限的右下角方块赋值为t涂第一象限其余的方块chessboar特殊方块就在第二象限chessboarelse涂第二象限其余的方块chessboardtr特殊方块就在第三象限cilessb0ardt涂第三象限其余的方块chessb0ardt特殊方块就在第四象限chessb0ardtelsef第四象限的左上角方块赋值为t涂第四象限其余的方块chessboar下转第93页关于x2xs的计算程序中有具体的公式而其它一些软约束条件也可通过各种方法得到实现比如要照顾岁数大的教师的问题可在数据库中排序
计算机算法设计五大常用算法的分析及实例
计算机算法设计五⼤常⽤算法的分析及实例摘要算法(Algorithm)是指解题⽅案的准确⽽完整的描述,是⼀系列解决问题的清晰指令,算法代表着⽤系统的⽅法描述解决问题的策略机制。
也就是说,能够对⼀定规范的输⼊,在有限时间内获得所要求的输出。
如果⼀个算法有缺陷,或不适合于某个问题,执⾏这个算法将不会解决这个问题。
不同的算法可能⽤不同的时间、空间或效率来完成同样的任务。
其中最常见的五中基本算法是递归与分治法、动态规划、贪⼼算法、回溯法、分⽀限界法。
本⽂通过这种算法的分析以及实例的讲解,让读者对算法有更深刻的认识,同时对这五种算法有更清楚认识关键词:算法,递归与分治法、动态规划、贪⼼算法、回溯法、分⽀限界法AbstractAlgorithm is the description to the problem solving scheme ,a set of clear instructions to solve the problem and represents the describe the strategy to solve the problem using the method of system mechanism . That is to say, given some confirm import,the Algorithm will find result In a limited time。
If an algorithm is defective or is not suitable for a certain job, it is invalid to execute it. Different algorithms have different need of time or space, and it's efficiency are different.There are most common algorithms: the recursive and divide and conquer、dynamic programming method、greedy algorithm、backtracking、branch and bound method.According to analyze the five algorithms and explain examples, make readers know more about algorithm , and understand the five algorithms more deeply.Keywords: Algorithm, the recursive and divide and conquer, dynamic programming method, greedy algorithm、backtracking, branch and bound method⽬录1. 前⾔ (4)1.1 论⽂背景 (4)2. 算法详解 (5)2.1 算法与程序 (5)2.2 表达算法的抽象机制 (5)2.3 算法复杂性分析 (5)3.五中常⽤算法的详解及实例 (6)3.1 递归与分治策略 (6)3.1.1 递归与分治策略基本思想 (6)3.1.2 实例——棋盘覆盖 (7)3.2 动态规划 (8)3.2.1 动态规划基本思想 (8)3.2.2 动态规划算法的基本步骤 (9)3.2.3 实例——矩阵连乘 (9)3.3 贪⼼算法 (11)3.3.1 贪⼼算法基本思想 (11)3.3.2 贪⼼算法和动态规划的区别 (12)3.3.3 ⽤贪⼼算法解背包问题的基本步骤: (12)3.4 回溯发 (13)3.4.1 回溯法基本思想 (13)3.3.2 回溯发解题基本步骤 (13)3.3.3 实例——0-1背包问题 (14)3.5 分⽀限界法 (15)3.5.1 分⽀限界法思想 (15)3.5.2 实例——装载问题 (16)总结 (18)参考⽂献 (18)1. 前⾔1.1 论⽂背景算法(Algorithm)是指解题⽅案的准确⽽完整的描述,是⼀系列解决问题的清晰指令,算法代表着⽤系统的⽅法描述解决问题的策略机制。
棋盘覆盖问题算法思路
棋盘覆盖问题算法思路
棋盘覆盖问题是一道经典的分治算法问题,通常用于介绍分治算法的思想。
其基本思路是将棋盘分成若干个小块,然后在其中一个小块上放置一块特殊的骨牌,然后将剩下的小块按照同样的方式继续分成更小的块,并在其中一个小块上放置另一块骨牌,以此类推,直到整个棋盘被覆盖。
具体的实现过程可以采用递归的方式,将棋盘不断地分成四个部分,然后在其中一个部分上放置一块骨牌,再递归求解另外三个部分。
在实现过程中,需要注意处理边界条件和特殊情况,例如棋盘大小为1x1或者存在特殊方块无法覆盖等情况。
该算法的时间复杂度为O(2^n),其中n为棋盘大小的指数。
虽然时间复杂度较高,但是由于该问题特殊的递归性质使得其能够被高效地并行化,因此在实际应用中仍有广泛的应用。
最小权顶点覆盖问题分支界限法
最小权顶点覆盖问题分支界限法最小权顶点覆盖问题是一个经典的组合优化问题。
该问题可以描述为:给定一个无向图G=(V,E),图中每个顶点v都有一个权值w(v),要求找到最小的顶点集合C,使得对于图中的每条边(u,v),至少有一个顶点在C中。
同时,要求C中所有顶点的权值之和最小。
分支界限法是一种解决组合优化问题的算法。
它通过将问题划分为若干个子问题,并对每个子问题进行求解和限界,从而逐步找到最优解。
下面是使用分支界限法求解最小权顶点覆盖问题的详细步骤:1. 定义问题的数学模型。
将最小权顶点覆盖问题表示为一个整数线性规划问题,目标函数为最小化C中顶点的权值之和,约束条件为每条边至少有一个顶点在C中。
2. 构造初始解。
初始化一个空的顶点集合C,将问题表示为一个根节点。
3. 基于当前解构造子问题。
从图中选择一个未被覆盖的顶点v,将其加入C中。
将问题分为两个子问题:子问题1是从图中删除顶点v及其相关的边,子问题2是从图中删除顶点v的邻居及其相关的边。
4. 求解子问题。
对两个子问题分别应用分支界限法进行求解。
对子问题1,建立新的根节点,并更新C;对子问题2,将v加入C,并更新问题。
5. 更新最优解。
每当找到一个新的最优解时,更新最优解的权值之和,并记录下来。
同时,记录下来所有已解的子问题。
6. 剪枝操作。
根据已解的子问题和最优解进行剪枝操作,减少搜索空间。
7. 重复步骤3-6,直到找到最优解或搜索空间为空。
在进行分支界限法求解最小权顶点覆盖问题时,可以采用以下的优化策略:1. 首先根据顶点的权值进行排序,优先选择权值较小的顶点进行划分。
这样可以在尽可能少地搜索空间的情况下找到最优解。
2. 使用线性规划松弛技术对每个子问题进行限界。
通过找到整数线性规划问题的线性松弛下界,可以快速排除那些不可能成为最优解的子问题。
3. 使用启发式算法进行问题求解。
通过结合启发式算法和分支界限法,可以在搜索空间较大时快速找到较优解。
分治法棋盘覆盖问题算法原理
分治法棋盘覆盖问题算法原理
分治法棋盘覆盖问题算法是一种基于分治策略的算法,用于解决棋盘覆盖问题。
该算法的基本原理是将一个复杂的问题分解为若干个较小的子问题,然后分别求解这些子问题,最后将子问题的解合并为原问题的解。
在棋盘覆盖问题中,给定一个n×n的棋盘,要求用最少的1×2骨牌覆盖整个棋盘。
分治法棋盘覆盖问题算法通过将棋盘不断划分,将问题规模逐渐减小,最终将问题转化为若干个1×1的棋盘覆盖问题,从而使得问题得以解决。
具体来说,该算法首先将棋盘划分为四个相等的子棋盘,然后判断哪个子棋盘中包含特殊方格。
对于不包含特殊方格的子棋盘,用L型骨牌覆盖其会合处,将其转化为特殊棋盘。
然后递归地使用这种划分策略,直至将棋盘分割为1×1的子棋盘。
通过这种分治策略,算法可以将问题规模不断减小,直到每个子问题都能够被直接解决。
最终,所有子问题的解将被合并为原问题的解。
这种算法不仅具有高效性,而且能够将复杂的问题分解为若干个简单的子问题,使得问题的解决更加容易。
算法设计与分析复习题目及答案
分治法1、二分搜索算法是利用(分治策略)实现的算法。
9. 实现循环赛日程表利用的算法是(分治策略)27、Strassen矩阵乘法是利用(分治策略)实现的算法。
34.实现合并排序利用的算法是(分治策略)。
实现大整数的乘法是利用的算法(分治策略)。
17.实现棋盘覆盖算法利用的算法是(分治法)。
29、使用分治法求解不需要满足的条件是(子问题必须是一样的)。
不可以使用分治法求解的是(0/1背包问题)。
动态规划下列不是动态规划算法基本步骤的是(构造最优解)下列是动态规划算法基本要素的是(子问题重叠性质)。
下列算法中通常以自底向上的方式求解最优解的是(动态规划法)备忘录方法是那种算法的变形。
(动态规划法)最长公共子序列算法利用的算法是(动态规划法)。
矩阵连乘问题的算法可由(动态规划算法B)设计实现。
实现最大子段和利用的算法是(动态规划法)。
贪心算法能解决的问题:单源最短路径问题,最小花费生成树问题,背包问题,活动安排问题,不能解决的问题:N皇后问题,0/1背包问题是贪心算法的基本要素的是(贪心选择性质和最优子结构性质)。
回溯法回溯法解旅行售货员问题时的解空间树是(排列树)。
剪枝函数是回溯法中为避免无效搜索采取的策略回溯法的效率不依赖于下列哪些因素(确定解空间的时间)分支限界法最大效益优先是(分支界限法)的一搜索方式。
分支限界法解最大团问题时,活结点表的组织形式是(最大堆)。
分支限界法解旅行售货员问题时,活结点表的组织形式是(最小堆)优先队列式分支限界法选取扩展结点的原则是(结点的优先级)在对问题的解空间树进行搜索的方法中,一个活结点最多有一次机会成为活结点的是( 分支限界法).从活结点表中选择下一个扩展结点的不同方式将导致不同的分支限界法,以下除( 栈式分支限界法)之外都是最常见的方式.(1)队列式(FIFO)分支限界法:按照队列先进先出(FIFO)原则选取下一个节点为扩展节点。
(2)优先队列式分支限界法:按照优先队列中规定的优先级选取优先级最高的节点成为当前扩展节点。
棋盘上的数学问题
希望杯
希望杯
学数
数学
竞 赛 题 竞 赛 题
(a)
(b)
图4
(要求 :每次移动网格中的字块时 ,只能
将字块滑动到相邻的空的网格中. )
(第 16 届“希望杯”全国数学邀请赛)
解 :将“希 、望 、杯 、数 、学 、竞 、赛 、题”八个
字分别记为 1 、2 、3 、4 、5 、6 、7 、8 ,则图 4 (a) 变为
③
a4 + a5 + a6 = 15.
④
①+ ②+ ③+ ④得
3 a5 + ( a1 + a2 + …+ a9 ) = 60 ,
即 3 a5 + 45 = 60 ,得 a5 = 5.
余下的 8 个数中有 4 个偶数 、4 个奇数.
若假设 a1 为奇数 ,则由式 ①知 a9 必为奇数.
分类讨论如下 :
14
综上 ,如图 8 所填的 3 ×3 棋盘 , 使 M 有最大 值 ,且最大值为 58.
注 :填数方法不唯一.
4 棋盘的覆盖问题
817 492 536
图8
这 里 的 覆 盖 问 题 是 指 最 简 单 的 一 类 覆
盖 ,即棋盘的完全覆盖 (在棋盘的覆盖中 ,各
个覆盖形的总格数等于棋盘的总格数) . 完全
在 3 ×3 网格的同一行中 ,按照要求调整 时 ,对应数字只能左右移动 ,移动前后的棋盘 所对应的八位数完全相同 ,相应的逆序的总 数不发生变化.
如果按照要求 ,将数字移动到相邻的行 中 ,相当于在对应的八位数中 ,将某个数字向 左 (或向右) 跳过了两个数字. 注意到在一个 多位数中 ,两个相邻数字交换位置 ,逆序总数 的变化量只能是 1 或 - 1 ,于是 ,将数字移动 到相邻的行时 ,对应的八位数的逆序总数的 变化量只能是 2 或 0 或 - 2.
棋盘覆盖(分治法)
}
/*left,top:方块的左上角坐标,x,y:特殊方块的坐标 size:当前的子棋盘大小*/
void ChessBoard(int left,int top,int x,int y,int size)
{
int i,t,s,pos;/*t是方块的编号,s是棋盘的一半尺寸!(size/2),pos表示方块位于哪一角 */
scanf("%d",&y);
if(k<0 || k>6 || x<0 || x>(size-1) || y<0 || y>(size-1))
{
printf("Input invalid!\n");
return;
}
InitGraph();
{
for(i=0;i<size;i++)
{
printf("%2d ",Board[i][j]);
}
printf("\n");
}
printf("\n--------------------------------\n");
{
setfillstyle(SOLID_FILL,color);
rectangle(BoardLeft+x*CellSize,BoardTop+y*CellSize,BoardLeft+(x+1)*CellSize,BoardTop+(y+1)*CellSize);
floodfill(BoardLeft+x*CellSize+CellSize/2,BoardTop+y*CellSize+CellSize/2,BorderColor);
分治算法详解及经典例题
分治算法详解及经典例题⼀、基本概念在计算机科学中,分治法是⼀种很重要的算法。
字⾯上的解释是“分⽽治之”,就是把⼀个复杂的问题分成两个或更多的相同或相似的⼦问题,再把⼦问题分成更⼩的⼦问题……直到最后⼦问题可以简单的直接求解,原问题的解即⼦问题的解的合并。
这个技巧是很多⾼效算法的基础,如排序算法(快速排序,归并排序),傅⽴叶变换(快速傅⽴叶变换)……任何⼀个可以⽤计算机求解的问题所需的计算时间都与其规模有关。
问题的规模越⼩,越容易直接求解,解题所需的计算时间也越少。
例如,对于n个元素的排序问题,当n=1时,不需任何计算。
n=2时,只要作⼀次⽐较即可排好序。
n=3时只要作3次⽐较即可,…。
⽽当n较⼤时,问题就不那么容易处理了。
要想直接解决⼀个规模较⼤的问题,有时是相当困难的。
⼆、基本思想及策略分治法的设计思想是:将⼀个难以直接解决的⼤问题,分割成⼀些规模较⼩的相同问题,以便各个击破,分⽽治之。
分治策略是:对于⼀个规模为n的问题,若该问题可以容易地解决(⽐如说规模n较⼩)则直接解决,否则将其分解为k个规模较⼩的⼦问题,这些⼦问题互相独⽴且与原问题形式相同,递归地解这些⼦问题,然后将各⼦问题的解合并得到原问题的解。
这种算法设计策略叫做分治法。
如果原问题可分割成k个⼦问题,1<k≤n,且这些⼦问题都可解并可利⽤这些⼦问题的解求出原问题的解,那么这种分治法就是可⾏的。
由分治法产⽣的⼦问题往往是原问题的较⼩模式,这就为使⽤递归技术提供了⽅便。
在这种情况下,反复应⽤分治⼿段,可以使⼦问题与原问题类型⼀致⽽其规模却不断缩⼩,最终使⼦问题缩⼩到很容易直接求出其解。
这⾃然导致递归过程的产⽣。
分治与递归像⼀对孪⽣兄弟,经常同时应⽤在算法设计之中,并由此产⽣许多⾼效算法。
三、分治法适⽤的情况分治法所能解决的问题⼀般具有以下⼏个特征:1) 该问题的规模缩⼩到⼀定的程度就可以容易地解决2) 该问题可以分解为若⼲个规模较⼩的相同问题,即该问题具有最优⼦结构性质。
算法设计与分析试题及答案
1.按分治策略求解棋盘覆盖问题时,对于如图所示的24X24的特殊棋盘,共需要多少个L型件牌:并在棋盘上填写L型骨牌的覆盖情况。
2.假设有7个物品,给出重疑和价值。
若这些物品均不能被分割,且背包容量M=140,使用回溯方法求解此0-1背包问题。
请画出状态空间搜索树。
3.假设有7个物品,它们的重量和价值如下表所示。
若这些物品均可以被分割,且背包容量M = 140,使用贪心算法求解此背包问题。
请写出求解策略和求解过程。
W (35,30,50,60,40,10,25) p (10,40,30,50,35,40,30)4.在给出的电路板中,阴彫部分是已作了封锁标记的方格,请按照队列式分支限界法在图中确立a到b的最短布线方案,要求布线时只能沿宜线或直角进行,在图中标岀求得最优解时各方格情况。
5.画出字符表的哈夫曼编码对应的二叉树。
6.己知4 = (cf)”* , k=\, 2» 3» 4. 5, 6, ri=5,门=10, /?=3,心=8, /3=5»门=20, rz=6,求矩阵链积A1XA2XA3XA4XA5XA6的最佳求积顺序。
7.给出城市网络图,售货员要从城市1岀发,经过所有城市回到城市1,画岀该问题的解空间树, 描述出用优先队列式分支限界法求解时的搜索情况。
表示出优先队列、当前扩展结点等的变化情况。
8.依据优先队列式分支限界法,求从s点到t点的单源最短路径,画出求得最优解的解空间树。
一、假设有7个物品,它们的重量和价值如下表所示。
若这些物品均不能被分割,且背包容量M = 150,使用回溯方法求解此背包问题。
请写岀状态空间搜索树(20分)。
答:按照单位效益从大到小依次排列这7个物品为:FBGDECA.将它们的序号分别记为1〜7。
则可生产如下的状态空间搜索树。
英中各个右点处的限界函数值通过如下方式求得:【排序1分】a. 40+40+30+50+35X 瞥"90.625 (山丄范。
中科院算法课程第2节-递归与分治
1. 如果Q中仅包含2个点,则返回这个点对; 2. 求Q中点的中位数m。
Divide: 1. 用Q中点坐标中位数m把Q划分为两个 大小相等的子集合 Q1 = {xQ | xm}, Q2 = {xQ | x>m}
2013-4-25
20
2.5 最近点对问题
• 利用排序的算法
– 算法
• 把Q中的点排序 • 通过排序集合的线性扫描找出最近点对 – 时间复杂性 • T(n)=O(nlogn)
2013-4-25
21
2.5 最近点对问题
一维最近点对的Divide-and-conquer算法
Preprocessing:
10
2.3 分治算法—设计
• 设计过程分为三个阶段
Divide:
整个问题划分为多个子问题
Conquer:求解各子问题(递归调用正设计的算法)
Combine:合并子问题的解, 形成原始问题的解
• 分析过程
– 建立递归方程 – 求解
• 递归方程的建立方法
– 设输入大小为n, T(n)为时间复杂性 – 当n<c, T(n)=(1)
2013-4-25
18
2.4 棋盘覆盖问题
void chessBoard(int tr, int tc, int dr, int dc, int size) { board[tr + s - 1][tc + s] = t; if (size == 1) return; // 覆盖其余方格 int t = tile++, // L型骨牌号 chessBoard(tr, tc+s, tr+s-1, tc+s, s);} s = size/2; // 分割棋盘 // 覆盖左下角子棋盘 // 覆盖左上角子棋盘 if (dr >= tr + s && dc < tc + s) if (dr < tr + s && dc < tc + s) // 特殊方格在此棋盘中 // 特殊方格在此棋盘中 chessBoard(tr+s, tc, dr, dc, s); chessBoard(tr, tc, dr, dc, s); else {// 用 t 号L型骨牌覆盖右上角 else {// 此棋盘中无特殊方格 board[tr + s][tc + s - 1] = t; // 用 t 号L型骨牌覆盖右下角 // 覆盖其余方格 board[tr + s - 1][tc + s - 1] = t; chessBoard(tr+s, tc, tr+s, tc+s-1, s);} // 覆盖其余方格 // 覆盖右下角子棋盘 // 覆盖右上角子棋chessBoard(tr, tc, tr+s-1, tc+s-1, s);}盘 s && dc >= tc + s) if (dr >= tr + if (dr < tr + s && dc >= tc + s) // 特殊方格在此棋盘中 // 特殊方格在此棋盘中 chessBoard(tr+s, tc+s, dr, dc, s); chessBoard(tr, tc+s, dr, dc, s); else {// 用 t 号L型骨牌覆盖左上角 else {// 此棋盘中无特殊方格 board[tr + s][tc + s] = t; // 用 t 号L型骨牌覆盖左下角 // 覆盖其余方格 chessBoard(tr+s, tc+s, tr+s, tc+s, s);} 2013-4-25 19 }
棋盘覆盖实验报告心得(3篇)
第1篇一、实验背景棋盘覆盖实验是计算机科学中一个经典的算法问题,旨在研究如何用最少数量的棋子覆盖整个棋盘。
这个实验不仅考验了我们对算法和数据结构的理解,还锻炼了我们的逻辑思维和编程能力。
在本实验中,我选择了使用回溯算法来解决棋盘覆盖问题,以下是我在实验过程中的心得体会。
二、实验目的1. 理解棋盘覆盖问题的背景和意义;2. 掌握回溯算法的基本原理和应用;3. 提高编程能力和逻辑思维能力;4. 分析不同算法的优缺点,为实际应用提供参考。
三、实验过程1. 确定问题模型棋盘覆盖问题可以抽象为一个二维数组,其中每个元素代表棋盘上的一个格子。
我们需要使用棋子(如皇后)来覆盖整个棋盘,使得每个格子都被至少一个棋子覆盖。
在本实验中,我们选择使用N皇后问题作为棋盘覆盖问题的子问题。
2. 设计算法为了解决棋盘覆盖问题,我们可以采用回溯算法。
回溯算法的基本思想是从一个解空间中搜索解,当找到一个解时,将其输出;当发现当前解不满足条件时,回溯到上一个状态,尝试其他可能的解。
具体步骤如下:(1)初始化棋盘,将所有格子设为未覆盖状态;(2)从第一行开始,尝试将棋子放置在该行第一个格子;(3)判断放置棋子后是否满足约束条件,如冲突、越界等;(4)如果满足约束条件,将该格子设为已覆盖状态,继续放置下一行棋子;(5)如果当前行已放置完棋子,检查是否覆盖了整个棋盘;(6)如果覆盖了整个棋盘,输出解;否则,回溯到上一个状态,尝试其他可能的解。
3. 编写代码根据上述算法,我使用Python语言实现了棋盘覆盖问题的回溯算法。
在代码中,我定义了一个二维数组来表示棋盘,并实现了放置棋子、检查约束条件、回溯等功能。
4. 实验结果与分析通过实验,我发现以下结论:(1)随着棋盘大小的增加,回溯算法的搜索空间也随之增大,导致算法的运行时间显著增加;(2)在解决N皇后问题时,当棋盘较大时,回溯算法的效率较低;(3)通过优化算法,如剪枝,可以提高算法的效率。
pascal竞赛试题及答案
一、单项选择题(共20题,每题1.5分,共计30分。
每题有且仅有一个正确答案。
)1.在以下各项中,()不是CPU的组成部分。
A.控制器B.运算器C.寄存器D.主板2.在关系数据库中,存放在数据库中的数据的逻辑结构以()为主。
A.二叉树B.多叉树C.哈希表D.二维表3.在下列各项中,只有()不是计算机存储容量的常用单位。
A.Byte B.KB C.UB D.TB4.ASCII码的含义是()。
A.二→十进制转换码B.美国信息交换标准代码C.数字的二进制编码D.计算机可处理字符的唯一编码5.一个完整的计算机系统应包括()。
A.系统硬件和系统软件B.硬件系统和软件系统C.主机和外部设备D.主机、键盘、显示器和辅助存储器6.IT的含义是()。
A.通信技术B.信息技术C.网络技术D.信息学7.LAN的含义是()。
A.因特网B.局域网C.广域网D.城域网8.冗余数据是指可以由其它数据导出的数据。
例如,数据库中已存放了学生的数学、语文和英语的三科成绩,如果还存放三科成绩的总分,则总分就可以看作冗余数据。
冗余数据往往会造成数据的不一致。
例如,上面4个数据如果都是输入的,由于操作错误使总分不等于三科成绩之和,就会产生矛盾。
下面关于冗余数据的说法中,正确的是()。
A.应该在数据库中消除一切冗余数据B.用高级语言编写的数据处理系统,通常比用关系数据库编写的系统更容易消除冗余数据C.为了提高查询效率,在数据库中可以保留一些冗余数据,但更新时要做相容性检验D.做相容性检验会降低效率,可以不理睬数据库中的冗余数据9.在下列各软件,不属于NOIP竞赛(复赛)推荐使用的语言环境有()。
A.gcc B.g++ C.Turbo C D.Free Pascal10.以下断电后仍能保存数据的有()。
A.硬盘B.高速缓存C.显存D.RAM11.在下列关于计算机语言的说法中,正确的有()。
A.高级语言比汇编语言更高级,是因为它的程序的运行效率更高B.随着Pascal、C等高级语言的出现,机器语言和汇编语言已经退出了历史舞台C.高级语言比汇编语言程序更容易从一种计算机上移植到另一种计算机上D.C是一种面向对象的高级计算机语言12.近20年来,许多计算机专家都大力推崇递归算法,认为它是解决较复杂问题的强有力的工具。
算法选择题(初级版 )256道
算法选择题(初级版)256道1.二分搜索算法是利用()实现的算法。
[单选题] *A.分治策略(正确答案)B.动态规划法C.贪心法D.回溯法2.回溯法解旅行售货员问题时的解空间树是()。
[单选题] *A.子集树B.排列树(正确答案)C.深度优先生成树D.广度优先生成树3.下列算法中通常以自底向上的方式求解最优解的是()。
[单选题] *A.备忘录法B.动态规划法(正确答案)C.贪心法D.回溯法4.下面不是分支界限法搜索方式的是()。
[单选题] *A.广度优先B.最小耗费优先C.最大效益优先D.深度优先(正确答案)5.采用贪心算法的最优装载问题的主要计算量在于将集装箱依其重量从小到大排序,故算法的时间复杂度为()。
[单选题] *A.O(n2^n)B.O(nlogn)(正确答案)C.O(2^n)D.O(n)6. 分支限界法求解最大团问题时,活结点表的组织形式是()。
[单选题] *A.最小堆B.最大堆(正确答案)C.栈D.数组7. 下面问题()不能使用贪心法解决。
[单选题] *A.单源最短路径问题B.N皇后问题(正确答案)C.最小花费生成树问题D.背包问题8. 下列算法中不能解决0/1 背包问题的是()。
[单选题] *A.贪心法(正确答案)B.动态规划C.回溯法D.分支限界法9. 背包问题的贪心算法所需的计算时间为()。
[单选题] *A.O(n2n)B.O(nlogn)(正确答案)C.O(2n)D.O(n)10. 二分查找是利用()实现的算法。
[单选题] *A. 分治策略(正确答案)B. 动态规划法C. 分支限界法D. 概率算法11. 下列不是动态规划算法基本步骤的是()。
[单选题] *A.找出最优解的性质B.构造最优解(正确答案)C.算出最优解D.定义最优解12. 最大效益优先是()的一种搜索方式。
[单选题] *A.分支界限法(正确答案)B.动态规划法C.贪心法D.回溯法13. 在下列算法中有时找不到问题解的是()。
棋盘覆盖问题
分治法棋盘覆盖声明:本文使用的代码和例子的来源:《计算机算法设计与分析》(王晓东编著,电子工业出版社)。
我对代码做了少许修改,使可以在tc的图形模式下看到题目的结果。
题目:在一个(2^k)*(2^k)个方格组成的棋盘上,有一个特殊方格与其他方格不同,称为特殊方格,称这样的棋盘为一个特殊棋盘。
现在要求对棋盘的其余部分用L型方块填满(注:L 型方块由3个单元格组成。
即围棋中比较忌讳的愚形三角,方向随意),切任何两个L型方块不能重叠覆盖。
L型方块的形态如下:■■■■■■■,■ ,■■ ,■■题目的解法使用分治法,即子问题和整体问题具有相同的形式。
我们对棋盘做一个分割,切割一次后的棋盘如图1所示,我们可以看到棋盘被切成4个一样大小的子棋盘,特殊方块必定位于四个子棋盘中的一个。
假设如图1所示,特殊方格位于右上角,我们把一个L型方块(灰色填充)放到图中位置。
这样对于每个子棋盘又各有一个“特殊方块”,我们对每个子棋盘继续这样分割,知道子棋盘的大小为1为止。
用到的L型方块需要(4^k-1)/3 个,算法的时间是O(4^k),是渐进最优解法。
本题目的C语言的完整代码如下(TC2.0下调试),运行时,先输入k的大小,(1<=k< =6),然后分别输入特殊方格所在的位置(x,y), 0<=x,y<=(2^k-1)。
程序将绘制出覆盖后的棋盘,运行效果截图如图2所示。
[此程序在TC下课成功运行。
VC下缺少头文件<graphics.h>,编译时会出现错误。
]#include <stdio.h>#include <graphics.h>/*#include <cpyscr.h>*/#define N 64#define BoardLeft 2#define BoardTop 2int Board[N][N]; /*棋盘*/int tile;/*全局性质的L图形编号*/int CellSize=10;/*网格大小*/int BorderColor=LIGHTGRAY;/*用指定颜色填充一个单元格!*/void PutCell(int x,int y,int color){setfillstyle(SOLID_FILL,color);rectangle(BoardLeft+x*CellSize,BoardTop+y*CellSize,BoardLeft+(x+1) *CellSize,BoardTop+(y+1)*CellSize);floodfill(BoardLeft+x*CellSize+CellSize/2,BoardTop+y*CellSize+Cel lSize/2,BorderColor);}/*绘制L方块,(cx,cy)是L方块的中心点CELL坐标,pos从1到4,表示位于特殊方块位于哪个角(即缺失的一角位置)*/void PutBlock(int cx,int cy,int pos){int x,y,t=CellSize;/*方块起始点像素坐标*/x=BoardLeft+cx*CellSize;y=BoardTop+cy*CellSize;moveto(x,y);/*移动到中心点*/switch(pos){case 1:/*左上角缺*/lineto(x,y-t);lineto(x+t,y-t);lineto(x+t,y+t);lineto(x-t,y+t);lineto(x-t,y);break;case 2:/*右上角缺*/lineto(x+t,y);lineto(x+t,y+t);lineto(x-t,y+t);lineto(x-t,y-t);lineto(x,y-t);break;case 3:/*左下角缺*/lineto(x-t,y);lineto(x-t,y-t);lineto(x+t,y-t);lineto(x+t,y+t);lineto(x,y+t);break;case 4:/*右下角缺*/lineto(x,y+t);lineto(x-t,y+t);lineto(x-t,y-t);lineto(x+t,y-t);lineto(x+t,y);break;}lineto(x,y);/*回到闭合点!*/}/*初始化图形模式*/void InitGraph(){int gdriver=DETECT,gmode;initgraph(&gdriver,&gmode,"");setcolor(BorderColor);}/*关闭图形模式*/void CloseGraph(){closegraph();}/*打印棋盘*/void PrintBoard(int size){int i,j;clrscr();for(j=0;j<size;j++){for(i=0;i<size;i++){printf("%2d ",Board[i][j]);}printf("\n");}printf("\n--------------------------------\n");printf("size=%d;\n");}/*left,top:方块的左上角坐标,x,y:特殊方块的坐标 size:当前的子棋盘大小*/void ChessBoard(int left,int top,int x,int y,int size){int i,t,s,pos;/*t是方块的编号,s是棋盘的一半尺寸!(size/2),pos表示方块位于哪一角 */if(size==1)return;t=tile++;/*当前L行方块的编号!递增*/s=size/2;/*------------处理左上角----------*/if(x<left+s && y<top+s){ChessBoard(left,top,x,y,s);/*设置位于左上角的标识*/ pos=1;}else{Board[left+s-1][top+s-1]=t; /*不在左上角*/ ChessBoard(left,top,left+s-1,top+s-1,s);}/*------------处理右上角----------*/if(x>=left+s && y<top+s){ChessBoard(left+s,top,x,y,s);pos=2;}else{Board[left+s][top+s-1]=t;/*不在右上角*/ChessBoard(left+s,top,left+s,top+s-1,s);}/*------------处理左下角----------*/if(x<left+s && y>=top+s){ChessBoard(left,top+s,x,y,s);pos=3;}else{Board[left+s-1][top+s]=t;ChessBoard(left,top+s,left+s-1,top+s-1,s);}/*------------处理右下角----------*/if(x>=left+s && y>=top+s){ChessBoard(left+s,top+s,x,y,s);pos=4;}else{Board[left+s][top+s]=t;ChessBoard(left+s,top+s,left+s,top+s,s);}/*画出当前的L方块*/PutBlock(left+s,top+s,pos);}void main(){int size,k,x,y,i,j;printf("please input k=? (k should not more than 6, boardsize=2^k ): \n");scanf("%d",&k);size=1<<k;printf("please input position of the special cell. x=? (not more than %d): \n",size-1);scanf("%d",&x);printf("please input position of the special cell. y=? (not more than %d): \n",size-1);scanf("%d",&y);if(k<0 || k>6 || x<0 || x>(size-1) || y<0 || y>(size-1)){printf("Input invalid!\n");return;}InitGraph();tile=1;Board[x][y]=0;/*绘制特殊方块!*/PutCell(x,y,RED);ChessBoard(0,0,x,y,size);/*CopyScreen("c:\\tc\\temp\\chess.bmp",0,0,400,400);*/getch();CloseGraph();}2.#include"stdio.h"#include<graphics.h>#include<dos.h>#include<math.h>int tile=1;int avg;int basex,basey;void chessboard(int tr,int tc,int dr,int dc,int size)/*加了一个int tc*/{int s,t;if(size==1)return;t=tile++;s=size/2;delay(150000);setfillstyle(7,1);sound(500);delay(1500);sound(400);delay(1500);nosound();bar(dr*avg+basex,dc*avg+basey,(dr+1)*avg+basex,(dc+1)*avg+basey);if((dr*avg+basex)<tr+s*avg&&(dc*avg+basey)<tc+s*avg)chessboard(tr,tc,dr,dc,s);else{setfillstyle(1,t);bar(tr+(s-1)*avg,tc+(s-1)*avg,tr+s*avg,tc+s*avg);chessboard(tr,tc,(tr-basex)/avg+s-1,(tc-basey)/avg+s-1,s);}if((dr*avg+basex)<tr+s*avg&&(dc*avg+basey)>=tc+s*avg)chessboard(tr,tc+s*avg,dr,dc,s);else{setfillstyle(1,t);bar(tr+(s-1)*avg,tc+s*avg,tr+s*avg,tc+(s+1)*avg);/*在这加了一个tr+ s*avg*/chessboard(tr,tc+s*avg,(tr-basex)/avg+s-1,(tc-basey)/avg+s,s); }if((dr*avg+basex)>=tr+s*avg&&(dc*avg+basey)<tc+s*avg)chessboard(tr+s*avg,tc,dr,dc,s);else{setfillstyle(1,t);bar(tr+s*avg,tc+(s-1)*avg,tr+(s-1)*avg,tc+s*avg);chessboard(tr+s*avg,tc,(tr-basex)/avg+s,(tc-basey)/avg+s-1,s); }if((dr*avg+basex)>=tr+s*avg&&(dc*avg+basey)>=tc+s*avg)chessboard(tr+s*avg,tc+s*avg,dr,dc,s);else{setfillstyle(1,t);bar(tr+s*avg,tc+s*avg,tr+(s+1)*avg,tc+(s+1)*avg);chessboard(tr+s*avg,tc+s*avg,(tr-basex)/avg+s,(tc-basey)/avg+s,s);}}main(){int size,k;int dr,dc,tr,tc;int endx,endy;int i;double x,y;int gdriver=DETECT;int gmode=VGA;initgraph(&gdriver,&gmode,"");basex=300,basey=100;endx=basex+320;endy=basey+320;cleardevice();setcolor(12);settextstyle(2,0,8);outtextxy(20,20,"zhoumingjiang\n");/*改成了outtextxy函数~~*/ outtextxy(60,60,"designer:zhoumingjiang 25/10/2002");setbkcolor(BLACK);setcolor(RED);printf("\n\n\n");printf(" please input k: ");scanf("%d",&k);x=2;y=k;size=pow(x,y);avg=320/size;rectangle(basex,basey,endx,endy);for(i=0;i<=size;i++){setlinestyle(1,1,6);line(basex,basey+i*avg,endx,basey+i*avg);line(basex+i*avg,basey,basex+i*avg,endy);}printf(" please input dr,dc: ");scanf("%d,%d",&dc,&dr);tr=basex;tc=basey;chessboard(tr,tc,dr,dc,size);}3.棋盘覆盖(C语言)#include <stdio.h>#include <conio.h>#include <math.h>int title=1;int board[64][64];void chessBoard(int tr,int tc,int dr,int dc,int size) {int s,t;if(size==1) return;t=title++;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;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;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;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;chessBoard(tr+s,tc+s,tr+s,tc+s,s);}}void main(){ int dr=0,dc=0,s=1,i=0,j=0;printf("print in the size of chess:\n"); scanf("%d",&s);printf("print in specal point x,y:\n"); scanf("%d%d",&dr,&dc);if(dr<s && dc<s){chessBoard(0,0,dr,dc,s);for(i=0;i<s;i++){for(j=0;j<s;j++){printf("%4d",board[i][j]);}printf("\n");}}elseprintf("the wrong specal point!!\n"); getch();}。
- 1、下载文档前请自行甄别文档内容的完整性,平台不提供额外的编辑、内容补充、找答案等附加服务。
- 2、"仅部分预览"的文档,不可在线预览部分如存在完整性等问题,可反馈申请退款(可完整预览的文档不适用该条件!)。
- 3、如文档侵犯您的权益,请联系客服反馈,我们会尽快为您处理(人工客服工作时间:9:00-18:30)。
用分治法求解棋盘覆盖问题
棋盘覆盖问题
问题描述:
在一个2k ×2k (k ≥0)个方格组成的棋盘中,恰有一个方格与其他方格不同,称该方格为特殊方格。
显然,特殊方格在棋盘中出现的位置有4k 中情形,因而有4k 中不同的棋盘,图(a )所示是k=2时
16种棋盘中的一
个。
棋盘覆盖问题
要求用图(b )所示的4中不同形状的L 型骨牌覆盖给定棋盘上除特殊方格以外的所有方格,且热河亮哥L 型骨牌不得重复覆盖。
问题分析: K>0时,可将2k ×2k 的棋盘划分为4个2k-1×2k-1的子棋盘。
这样划分后,由于原棋盘只有一个特殊方格,所以,这4个子棋盘中只有1个子
图(b ) 图 (a )
棋盘中有特殊方格,其余3个子棋盘中没有特殊方格。
为了将这3个没有特殊方格的子棋盘转化成为特殊棋盘,以便采用递归方法求解,可以用一个L型骨牌覆盖这3个较小的棋盘的会合处,从而将原问题转化为4个较小规模的棋盘覆盖问题。
递归地使用这种划分策略,直至将棋盘分割为1×1的子棋盘。
问题求解:
下面介绍棋盘覆盖问题中数据结构的设计。
(1)棋盘:可以用一个二维数组board[size][size]表示一个棋盘,其中
size=2k。
为了在递归处理的过程中使用同
一个棋盘,将数组board设为全局变量。
(2)子棋盘:整个棋盘用二维数组board[size][size]表示,其中的子棋盘
由棋盘左上角的下标tr、tc和棋盘大小s
表示。
(3)特殊方格:用board[dr][dc]表示特殊方格,dr和dc是该特殊方格在二维数组
board中的下标。
(4)L型骨牌:一个2k×2k的棋盘中有一个特殊方格,所以,用到L型骨牌的个数为
(4k-1)/3,将所有L型骨牌从1开始连续编号,用一个全局变量tile表示。
C语言源码:
/*author: 彭洪伟
*studentID:0950310006
*class:计科1班
*problem:分治法解决棋盘覆盖问题
*/
#include <stdio.h>
#include <math.h>
int tile=1; //记录骨牌的型号
int board[20][20]={0}; //存储棋盘被覆盖的情况
void ChessBoard(int tr,int tc,int dr,int dc,int size)
{ //tr和tc是棋盘左上角的下标,dr和dc是特殊方格的下标,size是棋盘的大小
int t=0;
int s;
if (size==1)return;
t=tile++;
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;
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;
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;
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;
ChessBoard(tr+s,tc+s,tr+s,tc+s,s);
}
}
int main()
{
int k,x,y;
printf("请输入棋盘的规模K:");
scanf("%d",&k);
printf("请输入特殊方格的下标x,y:");
scanf("%d %d",&x,&y);
ChessBoard(0,0,x,y,pow(2,k));
for(int i=0; i<pow(2,k); i++)
{
for (int j=0; j<pow(2,k); j++)
{
printf("%-4d",board[i][j]);
}
printf("\n");
}
return 0;
}
运行结果截图:。