棋盘覆盖问题(Tromino谜题)

合集下载

棋盘覆盖问题程序说明

棋盘覆盖问题程序说明

棋盘覆盖问题
对一M*N棋盘,假设有外形完全一样的骨排.每一骨排可覆盖棋盘上两相邻的方格.若用一些骨排覆盖棋盘,使棋盘上所有格被盖,且不交叉,称完全覆盖,.8*8棋盘是否可以完全覆盖?
编程思想:将棋盘设为一个M*N数组,对数组中每个元素分别赋值0和1,并使每个元素与其周围元素的值不相等。

再将数组中对角元素赋给0,1以外的值。

统计数组中0元素与1元素的个数。

若相等,证明可以完全覆盖,不相等则不能完全覆盖。

本程序特点:棋盘的行数和列数可以是任意的。

只需输入行数和列数便可得到结论。

缺点:棋盘只能是缺少对角的,不能是缺少任意的几格。

棋盘覆盖问题的求解

棋盘覆盖问题的求解

棋盘覆盖问题的求解棋盘覆盖问题是一个经典的数学问题,它引发了人们对于数学中的逻辑思维和问题解决能力的思考。

在这篇文章中,我将为大家详细介绍棋盘覆盖问题的求解方法,并希望能够帮助中学生和他们的父母更好地理解和应用这一问题。

棋盘覆盖问题是指如何用特殊形状的骨牌将一个2^n × 2^n的棋盘完全覆盖的问题。

其中,骨牌的形状分为4种,分别为L型、反L型、凸型和凹型。

在求解这个问题时,我们需要遵循以下几个步骤。

首先,我们需要将给定的棋盘划分为四个相等的小棋盘。

这样,我们就可以将问题分解为四个子问题,分别是将四个小棋盘覆盖完整。

接下来,我们就可以通过递归的方式来解决每个子问题。

在解决子问题时,我们需要根据骨牌的形状来选择放置的位置。

以L型骨牌为例,我们可以将其放置在左上角、左下角或者右上角。

通过不同的放置位置,我们可以将子问题进一步分解为更小的子问题。

同样地,我们可以使用相同的方法来解决反L型、凸型和凹型骨牌。

在每个子问题中,我们需要注意两个关键点。

首先,我们需要保证每个小棋盘上的骨牌能够完全覆盖。

这就要求我们在放置骨牌时,需要选择合适的位置和方向。

其次,我们需要保证四个小棋盘的边缘能够对齐。

这样,才能保证最终的结果是一个完整的棋盘。

通过不断地递归求解子问题,我们最终可以将整个棋盘完全覆盖。

这个过程中,我们需要注意边界条件的处理,以及递归函数的设计。

同时,我们还可以通过剪枝等优化方法来提高算法的效率。

棋盘覆盖问题的求解方法不仅仅是一个数学问题,更是一个思维训练的过程。

通过解决这个问题,我们可以培养自己的逻辑思维能力、问题解决能力和创新思维。

同时,这个问题也具有一定的实用性,可以用于解决一些实际问题,如图像处理、计算机视觉等领域。

总结一下,棋盘覆盖问题是一个经典的数学问题,通过将棋盘划分为四个小棋盘,我们可以通过递归的方式来解决每个子问题。

在解决子问题时,我们需要选择合适的骨牌形状和放置位置,同时保证边缘对齐和完全覆盖。

2020小学六年级奥数知识点:第十一讲 棋盘中的数学—棋盘覆盖的问题

2020小学六年级奥数知识点:第十一讲 棋盘中的数学—棋盘覆盖的问题
例3 在下图(1)、(2)、(3)、(4)四个图形中:
解:图形(1)和(2)中各有11个方格,11不是3的倍数,因此不能用这两种图形拼成.
图形来拼.
只有图形(4)可以用这两种三个方格的图形来拼,具体拼法有多种,下图仅举出一种为例.
说明:排除图(1)与(2)的方法是很重要的.因为一个图形可以用这是“必要条件排除法”.但要注意,一个图形小方格数是3的倍数,也不表明的就是这种情况.
证明:用6种“方块”构成4×7棋盘已如上图所示.
下面我们证明不能用七种“方块”各一块构成4×7的长方形棋盘.
将长方形的28个小方格如右图黑、白相间进行染色,则黑、白格各为个白格1个黑格,而其余六种方块图形皆占据黑格、白格各2个.因此,7种方块图形占据的黑白格数必都是奇数,不会等于14.
这类问题,容易更加一般化,即用2×1的方格骨牌去覆盖一个m×n的方格棋盘的问题.
定理1: m×n棋盘能被2×1骨牌覆盖的充分且必要的条件是m、n中至少有一个是偶数.
证明:①充分性:即已知m,n中至少有一个偶数,求证:m×n棋盘可被2×1骨牌覆盖.不失一般性,设m=2k,则m×n=2k×n=k×
棋盘可被kn个2×1骨牌覆盖.
②必要性:即已知m×n棋盘可以被2×1骨牌覆盖.求证:m,n中至少有一个偶数.若m×n棋盘可被2×1骨牌覆盖,则必覆盖偶数个方格,即mn是个偶数,因此m、n中至少有一个是偶数.
例2 下图中的8×8棋盘被剪去左上角与右下角的两个小方格,问能否用31个2×1的骨牌将这个剪残了的棋盘盖住?
第二步:不用1×1而只用2×2与3×3的正方形是拼不成的.将23×23的大正方形的1,4,7,10,13,16,19,22各行染红色,其余各行染蓝色如下图.任意2×2或3×3正方形都将包含偶数个蓝色小格,但蓝格总数是23×15,是个奇数,矛盾.所以不用1×1的小正方形是拼不成23×23棋盘的.

棋盘覆盖问题算法思路

棋盘覆盖问题算法思路

棋盘覆盖问题算法思路棋盘覆盖问题是一个经典的递归问题,其原始问题定义如下:给定一个2^n*2^n的棋盘,其中一个方格被标记,将该棋盘分割成4个2^(n-1)*2^(n-1)的小棋盘,同时以递归的方式,将标记方格分割到4个小棋盘之一,并覆盖其他方格。

重复此过程,直到达到基本情况,即当棋盘大小为2*2,无需分割。

我们可以使用分治法来解决这个问题,即将一个大问题分解为多个小问题,并最终将它们的解组合起来得到原问题的解。

下面是一个算法思路:1.定义一个棋盘的类,表示一个棋盘对象。

其中包括棋盘的大小、标记方格的位置坐标等信息。

2. 定义一个递归函数cover(board, size, tr, tc, dr, dc),其中board表示当前的棋盘对象,size表示当前棋盘的大小,(tr, tc)表示当前棋盘左上角方格的坐标,(dr, dc)表示标记方格的坐标。

3.首先检查当前棋盘大小是否为2*2,如果是,则直接将标记方格的位置填充到其他3个方格,并返回。

4. 否则,将当前棋盘的大小减半,计算出当前棋盘分割后4个小棋盘的左上角方格坐标和标记方格的位置坐标(nt, nl, nr, nc)。

5. 然后分别递归调用cover函数对4个小棋盘进行覆盖,需要注意传递的参数:a. 对于第一个小棋盘,其大小为size / 2,左上角坐标为(tr, tc),标记方格的坐标为(nt, nl)。

b. 对于第二个小棋盘,其大小为size / 2,左上角坐标为(tr, tc + size / 2),标记方格的坐标为(nr, nc)。

c. 对于第三个小棋盘,其大小为size / 2,左上角坐标为(tr + size / 2, tc),标记方格的坐标为(nr, nc)。

d. 对于第四个小棋盘,其大小为size / 2,左上角坐标为(tr + size / 2, tc + size / 2),标记方格的坐标为(nt, nl)。

6.最后,将4个小棋盘的覆盖结果组合起来得到原问题的解,并将该结果填充到当前棋盘。

棋盘覆盖算法

棋盘覆盖算法

棋盘覆盖算法棋盘覆盖算法(Tiling Puzzle)是用小的拼图块填满一个大的棋盘的问题,这些拼图块称作多米诺骨牌,每一块都覆盖两个格子,而棋盘的大小为2的n次方×2的n次方,其中n是整数。

在一个棋盘和一组多米诺骨牌下,棋盘恰好可以被所有的多米诺骨牌覆盖,且每个多米诺骨牌恰好覆盖两个格子。

棋盘覆盖算法是一个NP难问题,它需要在指数时间内找到最佳解决方案。

但是,对于许多小规模的问题,我们可以使用回溯算法来得到最佳解决方案。

回溯算法是一种试探性算法,最初解答第一个问题,可进一步解答其他问题。

该算法探讨所有可能的解决方案,直到找到正确的方案。

如果没有正确的解决方案,那么回溯算法将返回到较早的步骤并尝试其他方案。

因此,我们可以使用回溯算法来解决这个问题。

当我们覆盖一个多米诺骨牌时,我们可以检查是否存在其他多米诺骨牌可以覆盖未覆盖的部分,并将这些多米诺骨牌添加到棋盘的布局中。

如果我们在棋盘上填好所有的多米诺骨牌,那么我们就找到了正确的解决方案。

步骤:1. 首先在棋盘上选择一个没有被覆盖的格子。

2. 从所有可以放置在这个格子上的多米诺骨牌中,选择一个多米诺骨牌放到这个位置上。

3. 如果这个多米诺骨牌可以被放置在棋盘上的其他未被覆盖的位置上,那么就在这个位置上放置。

4. 重复步骤2和3,一直到所有的多米诺骨牌都被放置在棋盘上。

5. 如果无法放置更多的多米诺骨牌了,那么我们就找到了一个正确的解决方案。

如果仍有多米诺骨牌没有被放置,那么我们就返回步骤2,并尝试用其他的多米诺骨牌进行覆盖。

6. 最终,我们找到的正确的解决方案就是把所有多米诺骨牌都放置在位置上的布局。

总之,棋盘覆盖算法是一个重要的问题,它在计算机科学领域中具有广泛的应用。

在实际应用中,我们可以使用计算机来解决这个问题,例如利用回溯算法。

小学六年级奥数★棋盘的覆盖

小学六年级奥数★棋盘的覆盖

棋盘的覆盖同学们会下棋吗?下棋就要有棋盘,下面是中国象棋的棋盘(图1),围棋棋盘(图2)和国际象棋棋盘(图3)。

用某种形状的卡片,按一定要求将棋盘覆盖住,就是棋盘的覆盖问题。

例1要不重叠地刚好覆盖住一个正方形,最少要用多少个下图所示的图形?例2 能否用17个形如的卡片将下图刚好覆盖?例3 下图的七种图形都是由4个相同的小方格组成的。

现在要用这些图形拼成一个4×7的长方形(可以重复使用某些图形),那么,最多可以用上几种不同的图形?例4 用1×1,2×2,3×3的小正方形拼成一个11×11的大正方形,最少要用1×1的正方形多少个?例5用七个1×2的小长方形覆盖下图,共有多少种不同的覆盖方法?例6有许多边长为1厘米、2厘米、3厘米的正方形硬纸片。

用这些硬纸片拼成一个长5厘米、宽3厘米的长方形的纸板,共有多少种不同的拼法?(通过旋转及翻转能相互得到的拼法认为是相同的拼法)课后练习1.在4×4的正方形中,至少要放多少个形如所示的卡片,才能使得在不重叠的情形下,不能再在正方形中多放一个这样的卡片?(要求卡片的边缘与格线重合)2.下列各图中哪几个能用若干个或拼成?3.能否用9个形如的卡片覆盖住6×6的棋盘?4.小明有8张连在一起的电影票(如右图),他自己要留下4张连在一起的票,其余的送给别人。

他留下的四张票可以有多少种不同情况?5.有若干个边长为1、边长为2、边长为3的小正方形,从中选出一些拼成一个边长为4的大正方形,共有多少种不同拼法?(只要选择的各种小正方形的数目相同就算相同的拼法)6.用6个形如的卡片覆盖下图,共有多少种不同的覆盖方法?7.能不能用9个1×4的长方形卡片拼成一个6×6的正方形?答案与提示练习151.3个。

提示:左下图是一种放法。

2.图(2)。

提示:图(1)的小方格数不是3的倍数;图(3)的小方格数是3的倍数但拼不成;图(2)的拼法见右上图。

棋盘覆盖问题

棋盘覆盖问题

棋盘覆盖问题1.实验题目要求用4种不同形状的L型骨牌(分别为L旋转90度、180度、270度、360度所成图形,且每个图形均只含有三个小方格)覆盖给定棋盘上出特殊方格以外的所有方格,且任何两个L型骨牌不得重叠覆盖。

2.实验目的(1)进一步掌握递归算法的设计思想以及递归程序的调试技术;(2)理解这样一个观点:分治与递归经常同时应用在算法设计之中。

3.实验要求(1)用分治法解决棋盘覆盖问题;(2)分析算法的时间性能。

4.程序实现#include<stdio.h>#define N 4int board[N][N]={0};void ChessBoard(int tr,int tc,int dr,int dc,int size){int s;if(size==1) return;static int c=1;int t=c++;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 i,j;int a[N][N]={0};for(i=0;i<=N-1;i++){for(j=0;j<=N-1;j++){printf("%5d",a[i][j]);}printf("\n");}int tr=0,tc=0,dr,dc;printf("请在以上的棋盘中选择特殊方格的位置并输入其坐标(坐标计数从0开始):\n"); scanf("%d%d",&dr,&dc);ChessBoard(tr,tc,dr,dc,N);for(i=0;i<=N-1;i++){for(j=0;j<=N-1;j++){printf("%5d",board[i][j]);}printf("\n");}}5.时间复杂性分析设T(k)是覆盖一个2k×2k棋盘所需时间,从算法的划分策略可知,T(k)满足以下递推式:k=0时,T(k)=O(1);k>0时,T(k)=4T(k-1)+O(1);就此递推式可得T(k)=O(4k)。

棋盘覆盖问题的算法实现(代码及截图)

棋盘覆盖问题的算法实现(代码及截图)

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 i,j,k,a,b; printf("请输入特殊方格的坐标:"); scanf("%d %d",&a,&b); ChessBoard(0,0,a,b,4); for(k=0;k<tile;k++) { printf("编号为%d的型骨牌的坐标为:",k); for(i=0;i<4;i++) for(j=0;j<4;j++) { if(Board[i][j]==k&&(i!=a||j!=b)) printf("(%d,%d)",i,j); } printf("\n"); } }
棋盘覆盖问题的算法实现
在一个2^k * 2^k个方格组成的棋盘中,有一个方格与其它的 不同,若使用以下四种L型骨牌覆盖除这个特殊方格的其它方 格,如何覆盖。 四个L型骨牌如下图1

趣题:免分割线的多米诺骨牌覆盖方案

趣题:免分割线的多米诺骨牌覆盖方案

问题:能否用多米诺骨牌既无重复又无遗漏地覆盖一个6 × 6 的棋盘,使得棋盘上的每一条水平线和每一条竖直线都会穿过至少一个多米诺骨牌?举个例子,下图所示的棋盘覆盖方案就是不满足要求的,因为棋盘的第二条水平线不会切断任何一个多米诺骨牌。

满足要求的棋盘覆盖是不存在的。

我们有一个非常漂亮的证明。

注意到,任意一条水平线都会把整个棋盘分成上下两部分,这两部分所包含的小正方形的个数都是偶数。

那些完全在这条线上面的多米诺骨牌会占据其中偶数个格子,那些完全在这条线下面的多米诺骨牌也会占据其中偶数个格子,因而棋盘的上下两部分各剩下了偶数个格子,这些格子就留给了那些穿过了这条水平线的多米诺骨牌来占据。

每一个穿过了这条线的多米诺骨牌都会在上下两部分棋盘各占据一个格子,因此为了完全覆盖棋盘,这样的多米诺骨牌必须得有偶数个才行。

结论就是:在一个满足要求的棋盘覆盖方案中,每条水平线都会穿过至少两个多米诺骨牌。

同理,每条竖直线也都会穿过至少两个多米诺骨牌。

然而,在 6 × 6 的棋盘中,水平线和竖直线一共有10 条,每条线上都有两个多米诺骨牌,这显然是不现实的,因为整个棋盘里一共也只能放下18 个多米诺骨牌。

有趣的是,棋盘再稍微大一些,这种推理就失效了。

在一个8 × 8 的棋盘中,水平线和竖直线一共有14 条,它们对应于28 个多米诺骨牌,这却并不会导致矛盾,因为棋盘里一共能放下32 个多米诺骨牌。

那么,8 × 8 的棋盘是否存在满足要求的覆盖方案呢?更一般地,对于哪些正整数M 和N ,在一个M × N 的棋盘里存在满足要求的覆盖方案呢?注意,M 和N 这两个数当中至少得有一个数是偶数,否则整个棋盘将会有奇数个小方格,这根本不可能被多米诺骨牌既无重复又无遗漏地覆盖住。

不妨假设M ≤ N 。

M = 1 和M = 2 的情况基本上可以直接被排除了(不过,这里面有一个特例,即(M, N) = (1, 2) 可以算作是一个平凡解)。

棋盘覆盖问题

棋盘覆盖问题
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 { // 用 t 号L型骨牌覆盖右上角,再递归处理子棋盘
棋盘覆盖问题要求用如图(b)所示的L型骨 牌覆盖给定棋盘上除特殊方格以外的所有方格, 且骨牌之间不得有重叠。
(a) k=2时的一种棋盘
(b) 4种不同形状的L型骨牌
棋盘覆盖问题
残缺棋盘是一个有2k×2k (k≥1)个方格的棋盘,其中恰有 一个方格残缺。图4-7给出k=1时各种可能的残缺棋盘,其 中残缺的方格用阴影表示。
board[tr + s][tc + s] = t;
ChessBoard(tr+s, tc+s, tr+s, tc+s, s); }
}
#include <stdio.h>
#define N 16
int a[100][100];
int t=1;
void Tromino(int (*a)[N],int dr,int dc,int tr,int tc,int size)
图 一个4*4的残缺棋盘
从以上例子还可以发现,当残缺方格在第1个子棋盘,用① 号三格板覆盖其余三个子棋盘的交界方格,可以使另外三 个子棋盘转化为独立子问题;同样地(如下图所示),当 残缺方格在第2个子棋盘时,则首先用②号三格板进行棋盘 覆盖,当残缺方格在第3个子棋盘时,则首先用③号三格板 进行棋盘覆盖,当残缺方格在第4个子棋盘时,则首先用④ 号三格板进行棋盘覆盖,这样就使另外三个子棋盘转化为 独立子问题。如下图:

棋盘覆盖问题

棋盘覆盖问题

棋盘覆盖问题
有一个经典问题:8*8的棋盘,去掉了左下角和右上角2个格子,请问能否用31块1*2的骨牌覆盖整个棋盘。

这个问题的答案应该人人都知道吧,染色之后一目了然。

那么,有人要问了:如果去掉的是1红1白的格子各一个,结果是怎样的呢?比如下面的这个图:
你可以自己画几个图试一试。

你能证明一定可以覆盖?还是可以给出反例呢?
据说,这个问题刚出来的时候,通过复杂的理论,终于得到了证明。

也就是只要在这个图中去掉一红一白两格,肯定可以被覆盖。

这里,我们将看到一个复杂的问题怎么通过一个简单的方法来证明。

我们接下来不但要证明可以覆盖,而且要给出覆盖的方法。

看到这里你可能会想到了:构造——对了,只要构造了一组解,原问题便解决了。

我们把原来的棋盘按照下图所示的方法剪开:(沿着绿线):
我们就把这个棋盘变成了一个环。

注意到整个环都是红白相间的。

假设我们从图中去掉一个红色格子,再去掉一个白色格子。

我们就得到两条链:每一条链都是红色->白色->红色...->白色。

这样我们只要沿着链每次的两个格子放即可(注意到相连的两个格子不存在和骨牌形状不同的情况:1*2,你能找出第二种形状吗?)。

把两条链放完,这个棋盘就被覆盖满了,我们的问题也就解决了。

棋盘覆盖问题

棋盘覆盖问题

分治法棋盘覆盖声明:本文使用的代码和例子的来源:《计算机算法设计与分析》(王晓东编著,电子工业出版社)。

我对代码做了少许修改,使可以在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();}。

Tromino谜题

Tromino谜题

Tromino谜题题⽬:Tromino 谜题Tromino是指⼀个由棋盘上的三个1*1⽅块组成的 L 型⾻牌。

如何⽤ Tromino 覆盖⼀个缺少了了⼀个⽅块(可以在棋盘上任何位置)的2^n*2^n棋盘(下图展⽰了n=3情况)。

除了这个缺失的⽅块,Tromino应该覆盖棋盘上的所有⽅块,Tromino可以任意转向但不能由重叠。

设计内容及要求:(1)为此问题设计⼀个分治算法,分析算法的时间复杂度;(2)实现所设计的算法,并以图形化界⾯演⽰覆盖过程。

问题分析与解决思路解决思路1问题分析与通过对问题的分析,题⽬要求⽤分治法来解决该问题。

该问题中缺失⽅块的位置是任意的,棋盘⼤⼩是2的n次⽅(n为正整数)的矩阵,所以我们先来考虑最⼩规模即当n=1时的情况。

这种情况下⽆论缺失的⽅块在哪个位置,我们只需要将剩下的三个⽅块填充就好,相当于放置⼀个⾻牌。

当n=2时,⽅块数为4*4,划分⼦问题前,我们先将棋盘分为四个象限,确定缺失⽅块的象限后,将其它三个象限距离中⼼位置最近的⼀个⽅块填充。

此时我们再将其划分为四个⽅块数为2*2的矩阵,将已经填充的⽅块看作缺失⽅块,则每个⼩规模矩阵都有⼀个缺失⽅块,即它们是规模相同的⼦问题,依次递归最后将整个棋盘填充完整。

如图2.1.3所⽰,将8*8棋盘中的1,2,3填充后,再将其划分为四个部分得到如图2.1.2所⽰的4*4棋盘,将4*4棋盘中的1,2,3⽅块填充后再划分得到如图2.1.1所⽰的2*2棋盘,填充后继续递归最终完成整个棋盘的填充。

实际编程时可让相应的位置坐标赋值为k*i(k为中点位置,i为象限,i取值为1-4),界⾯动画展⽰时根据不同的值⽤不同颜⾊显⽰⽅块即可实现不同⾻牌的区分。

图1.1 n=1时填充图1.2 n=2 时填充及划分图1.3 n=3 时填充及划分2 模型建⽴与算法描述记棋盘为size*size的⼆维数组T,初始化为0,缺失⽅块位置为x,y,参数m、n分别记录棋盘横向位置的开始和结束(列的取值范围,更确切的说n为纵向长度,即下标的最⼤值+1),参数l,r分别记录棋盘纵向位置的开始和结束(⾏的取值范围,r同n)建⽴数学模型:T[k][j-1]=T[k][j]=T[k-1][j]=1*k,(x<k且y<j)T[k-1][j-1]=T[k][j]=T[k-1][j]=2*k,(x>=k且y<j)T[k-1][j-1]=T[k][j-1]=T[k-1][j]=3*k,(x>=k且y>=j)T[k-1][j-1]=T[k][j-1]=T[k][j]=4*k,(x<k且y>=j)其中k=(m+n)/2,j=(l+r)/2我们将上述分析过程和解决的思路进⼀步归纳为以下步骤:(1)如果n-m>=2,执⾏步骤(2),否则结束过程。

棋盘覆盖问题(Tromino谜题)

棋盘覆盖问题(Tromino谜题)

tc
tr
dc
dr
size
棋盘覆盖问题中的数据结构
算法——棋盘覆盖
void ChessBoard(int tr, int tc, int dr, int dc, int size)
// tr和tc是棋盘左上角的下标,dr和dc是特殊方格的下标,
// size是棋盘的大小,t已初始化为0
{
if (size = = 1) return; //棋盘只有一个方格且是特殊方格
t++; // L型骨牌号
s = size/2; // 划分棋盘
// 覆盖左上角子棋盘
if (dr < tr + s && dc < tc + s) // 特殊方格在左上角子棋盘中
ChessBoard(tr, tc, dr, dc, s);
//递归处理子棋盘
else{ // 用 t 号L型骨牌覆盖右下角,再递归处理子棋盘
tr:棋盘左上角方格的行号 tc:棋盘左上角方格的列号 dr:特殊方格所在的行号 dc:特殊方格所在的列号 size:方形棋盘的边长
#include <stdio.h>
#define N 16
int a[100][100];
int t=1;
void Tromino(int (*a)[N],int dr,int dc,int tr,int tc,int size)
for(j=0;j<N;j++) printf("%-4d",a[i][j]);
printf("\n"); } system("pause"); }
设T(k)是覆盖一个2k×2k棋盘所需时间,从 算法的划分策略可知,T(k)满足如下递推式:

棋盘覆盖问题(分治法)

棋盘覆盖问题(分治法)

棋盘覆盖问题(分治法)这⾥的前覆盖问题要涉及到分治法;分治法主要分三步:分解 -----> 求解 ------> 合并(1)分解:将⼀个⼤规模问题分解为有限个⼩规模的问题(⼩问题之间相互独⽴,并且它们的问题性质和原始问题的问题性质相同、独⽴),其实这点和递归有异曲同⼯之妙,其中⼩问题的规模为问题最⼩单位,分解的时候也是递归地分解;(2)求解:⼀般地,我们可以递归地求解这n个⼩问题;(3)合并:程序如下://棋盘覆盖问题,分治法算法#include <iostream>using namespace std;int tile = 1; //L型⾻牌的编号const int Maxnum = 1 << 10; //棋盘的尺⼨⼤⼩最⼤为2的10次⽅int Board[Maxnum][Maxnum]; //定义⼀个⼆维数组表⽰这个棋盘void ChessBoard(int tr, int tc, int dr, int dc, int size) //tr , tc分别代表左上⾓⾏号和列号,dr和dc分别代表特殊⽅块的⾏号和列号,size是棋盘的尺⼨{if (size == 1)return;int t = tile++; //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号L型⾻牌填充右下⾓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号L型⾻牌填充左下⾓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号L型⾻牌填充右上⾓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号L型⾻牌填充左上⾓ChessBoard(tr + s, tc + s, tr + s, tc + s, s); //递归}}int main(void){int x, y, size; //x , y分别代表特殊⽅块的位置,size代表棋盘的⼤⼩cout << "请输⼊特殊⽅块的位置(x,y)和棋盘的尺⼨⼤⼩size: ";cin >> x >> y >> size;if (size == 0){cout << "棋盘尺⼨输⼊不合法!" << endl;system("pause");return1;}else if (x >= size || y >= size){cout << "特殊⽅块的位置输⼊不合法!" << endl;system("pause");return1;}//特殊⽅块赋值为0Board[x][y] = 0;//分治法填满棋盘ChessBoard(0, 0, x, y, size);//输出棋盘for (int i = 0; i < size; i++){for (int j = 0; j < size; j++){cout << Board[i][j] << "\t"; }cout << endl << endl << endl; }system("pause");return0;}。

算法设计--普通背包问题与棋盘覆盖问题分析

算法设计--普通背包问题与棋盘覆盖问题分析

目录一、问题描述 (2)1、普通背包问题: (2)2、棋盘覆盖问题: (2)二、问题分析 (2)1、普通背包问题: (2)2、棋盘覆盖问题: (3)三、建立数学模型 (3)1、普通背包问题: (3)四、算法设计 (4)2、普通背包问题: (4)2、棋盘覆盖问题: (4)五、算法实现 (5)1、普通背包问题: (5)2、棋盘覆盖问题: (8)六、测试分析 (9)1、普通背包问题: (9)2、棋盘覆盖问题: (11)七、结论 (12)八、源程序 (12)1、普通背包问题: (12)2、棋盘覆盖问题: (15)九、参考文献: (16)一、问题描述1、普通背包问题:有一个背包容量为C,输入N个物品,每个物品有重量S[i],以及物品放入背包中所得的收益P[i]。

求选择放入的物品,不超过背包的容量,且得到的收益最好。

物品可以拆分,利用贪心算法解决。

2、棋盘覆盖问题:在一个2k×2k 个方格组成的棋盘中,恰有一个方格与其它方格不同,称该方格为一特殊方格,且称该棋盘为一特殊棋盘。

在棋盘覆盖问题中,要用图示的4种不同形态的L型骨牌覆盖给定的特殊棋盘上除特殊方格以外的所有方格,且任何2个L型骨牌不得重叠覆盖。

二、问题分析1、普通背包问题:贪心算法的基本思想是:从问题的某一个初始解出发逐步逼近给定的目标,以尽可能快的求得更好的解。

当达到算法中的某一步不能再继续前进时,算法停止。

背包问题用贪心算法来解决,先求出每件物品的平均价值即p[i]/s[i],然后每次选择利润p[i]/s[i]最大的物品装进背包,这样就使得目标函数增加最快,当最后一种物品放不下时,选择一个适当的拆分,使物品装满背包,使得总的价值最大。

2、棋盘覆盖问题:将2^k x 2^k的棋盘,先分成相等的四块子棋盘,其中特殊方格位于四个中的一个,构造剩下没特殊方格三个子棋盘,将他们中的也假一个方格设为特殊方格。

如果是:左上的子棋盘(若不存在特殊方格)则将该子棋盘右下角的那个方格假设为特殊方格右上的子棋盘(若不存在特殊方格)则将该子棋盘左下角的那个方格假设为特殊方格左下的子棋盘(若不存在特殊方格)则将该子棋盘右上角的那个方格假设为特殊方格右下的子棋盘(若不存在特殊方格)则将该子棋盘左上角的那个方格假设为特殊方格当然上面四种,只可能且必定只有三个成立,那三个假设的特殊方格刚好构成一个L型骨架,我们可以给它们作上相同的标记。

棋盘覆盖问题算法思路

棋盘覆盖问题算法思路

棋盘覆盖问题算法思路
棋盘覆盖问题是一道经典的分治算法问题,通常用于介绍分治算法的思想。

其基本思路是将棋盘分成若干个小块,然后在其中一个小块上放置一块特殊的骨牌,然后将剩下的小块按照同样的方式继续分成更小的块,并在其中一个小块上放置另一块骨牌,以此类推,直到整个棋盘被覆盖。

具体的实现过程可以采用递归的方式,将棋盘不断地分成四个部分,然后在其中一个部分上放置一块骨牌,再递归求解另外三个部分。

在实现过程中,需要注意处理边界条件和特殊情况,例如棋盘大小为1x1或者存在特殊方块无法覆盖等情况。

该算法的时间复杂度为O(2^n),其中n为棋盘大小的指数。

虽然时间复杂度较高,但是由于该问题特殊的递归性质使得其能够被高效地并行化,因此在实际应用中仍有广泛的应用。

棋盘覆盖实验报告

棋盘覆盖实验报告

棋盘覆盖实验报告棋盘覆盖实验报告引言:棋盘覆盖是一种经典的数学问题,它可以帮助我们理解数学中的一些概念和原理。

在这个实验中,我们将探讨棋盘覆盖问题,并通过实际操作来验证相关的数学理论。

实验目的:1. 理解棋盘覆盖问题的定义和原理;2. 通过实际操作,观察和分析棋盘覆盖的过程;3. 探索棋盘覆盖问题的解决方法。

实验材料:1. 一个8x8的棋盘;2. 32个L型骨牌,每个骨牌由3个方格组成。

实验步骤:1. 准备一个8x8的棋盘和32个L型骨牌。

2. 将棋盘放置在桌面上,并确保每个方格都是可见的。

3. 将骨牌放置在棋盘上,每个骨牌覆盖三个相邻的方格。

4. 继续放置骨牌,直到棋盘上的每个方格都被覆盖。

实验结果:经过仔细的操作,我们成功地将32个L型骨牌覆盖在了8x8的棋盘上,每个方格都被覆盖到。

分析和讨论:棋盘覆盖问题是一个经典的数学问题,它涉及到数学中的一些重要概念和原理。

在这个实验中,我们可以观察到以下几个方面:1. 骨牌的形状:L型骨牌由3个方格组成,其中两个方格在一条直线上,另一个方格位于直线的旁边。

这种形状决定了骨牌只能覆盖特定的方格组合。

2. 骨牌的数量:我们使用了32个L型骨牌来覆盖整个棋盘。

这是因为每个骨牌覆盖3个方格,而棋盘上共有64个方格,所以需要32个骨牌来完成覆盖。

3. 解决方法:在实验中,我们可以采用不同的方法来解决棋盘覆盖问题。

一种常见的方法是采用递归的思想,将棋盘分割成更小的部分,然后逐步覆盖。

这种方法可以确保每个方格都被覆盖到,并且不会出现重叠或遗漏的情况。

结论:通过这个实验,我们深入了解了棋盘覆盖问题,并通过实际操作验证了相关的数学理论。

我们发现,棋盘覆盖问题涉及到骨牌的形状、数量和解决方法等方面。

这个实验不仅加深了我们对数学问题的理解,还培养了我们的逻辑思维和问题解决能力。

附录:在这个实验中,我们使用了一个8x8的棋盘和32个L型骨牌。

然而,棋盘覆盖问题并不局限于这个规模,它可以扩展到更大的棋盘和更多的骨牌。

  1. 1、下载文档前请自行甄别文档内容的完整性,平台不提供额外的编辑、内容补充、找答案等附加服务。
  2. 2、"仅部分预览"的文档,不可在线预览部分如存在完整性等问题,可反馈申请退款(可完整预览的文档不适用该条件!)。
  3. 3、如文档侵犯您的权益,请联系客服反馈,我们会尽快为您处理(人工客服工作时间:9:00-18:30)。

tc
tr
dc
dr
size
棋盘覆盖问题中的数据结构
算法——棋盘覆盖
void ChessBoard(int tr, int tc, int dr, int dc, int size)
// tr和tc是棋盘左上角的下标,dr和dc是特殊方格的下标,
// size是棋盘的大小,t已初始化为0
{
if (size = = 1) return; //棋盘只有一个方格且是特殊方格
{
int s;
if(size==1) return;
if(size>1)
{
s=size/2;
if(dr<=(tr+s-1)&&dc<=(tc+s-1))
/*特殊方块在左上部分
*/
{
a[tr+s-1][tc+s]=t;
a[tr+s][tc+s]=t;
a[tr+s][tc+s-1]=t;
t++;
Tromino(a,dr,dc,tr,tc,s);
board[tr + s - 1][tc + s - 1] = t;
ChessBoΒιβλιοθήκη rd(tr, tc, tr+s-1, tc+s-1, s);
}
// 覆盖右上角子棋盘
if (dr < tr + s && dc >= tc + s) // 特殊方格在右上角子棋盘中
ChessBoard(tr, tc+s, dr, dc, s);
for(j=0;j<N;j++) printf("%-4d",a[i][j]);
printf("\n"); } system("pause"); }
设T(k)是覆盖一个2k×2k棋盘所需时间,从 算法的划分策略可知,T(k)满足如下递推式:
O(1)
k 0
T (k) 4T (k 1) O(1) k 0
Tromino(a,tr+s-1,tc+s,tr,tc+s,s);
Tromino(a,tr+s,tc+s,tr+s,tc+s,s);
Tromino(a,tr+s,tc+s-1,tr+s,tc,s);
if(dr<=(tr+s-1)&&dc>(tc+s-1))
/*特殊方块在右上部分*/
{
a[tr+s-1][tc+s-1]=t;
ChessBoard(tr+s, tc, dr, dc, s); //递归处理子棋盘
else { // 用 t 号L型骨牌覆盖右上角,再递归处理子棋盘
board[tr + s][tc + s - 1] = t;
ChessBoard(tr+s, tc, tr+s, tc+s-1, s); }
// 覆盖右下角子棋盘
2k-1×2k-1 2k-1×2k-1
2k-1×2k-1 2k-1×2k-1
(a)棋盘分割
(b) 构造相同子问题
下面介绍棋盘覆盖问题中数据结构的设计: (1)棋盘:用二维数组board[size][size]表示一 个棋盘,其中,size=2k。为了在递归处理的过程 中使用同一个棋盘,将数组board设为全局变量;
解此递推式可得T(k)=O(4k)。
}
if(dr>(tr+s-1)&&dc<=(tc+s-1)) /*特殊方块在左下部分*/
{
a[tr+s-1][tc+s-1]=t;
a[tr+s-1][tc+s]=t;
a[tr+s][tc+s]=t;
t++;
Tromino(a,dr,dc,tr+s,tc,s);
Tromino(a,tr+s-1,tc+s-1,tr,tc,s);
ChessBoard(tr+s, tc+s, tr+s, tc+s, s); }
}
问题描述:在一个2^k×2^k 个方格组成的棋盘中,恰有一 个方格与其它方格不同,称该方格为一特殊方格,且称该 棋盘为一特殊棋盘。在棋盘覆盖问题中,要用4种不同形态 的L型骨牌覆盖给定的特殊棋盘上除特殊方格以外的所有方 格,且任何2个L型骨牌不得重叠覆盖。 算法思想: 用分治策略,可以设计出解棋盘覆盖问题的简洁算法。 (1)当k>0时,将2的k次幂乘以2的k次幂棋盘分割为4个2的 k-1次幂乘以2的k-1次幂子棋盘。 (2)特殊方格必位于4个较小棋盘之一中,其余3个子棋盘中 无特殊方格。 (3)为了将这3个无特殊方格的子棋盘转化为特殊棋盘,可 以用一个L型骨牌覆盖这3个较小棋盘的会合处,这3个子棋 盘上被L型骨牌覆盖的方格就成为该棋盘上的特殊方格,从 而将原问题转化为4个较小规模的棋盘覆盖问题。递归地使 用这种分割,直至棋盘简化为1*1棋盘。
if (dr >= tr + s && dc >= tc + s) // 特殊方格在右下角子棋盘中
ChessBoard(tr+s, tc+s, dr, dc, s); //递归处理子棋盘
else { // 用 t 号L型骨牌覆盖左上角,再递归处理子棋盘
board[tr + s][tc + s] = t;
t++; // L型骨牌号
s = size/2; // 划分棋盘
// 覆盖左上角子棋盘
if (dr < tr + s && dc < tc + s) // 特殊方格在左上角子棋盘中
ChessBoard(tr, tc, dr, dc, s);
//递归处理子棋盘
else{ // 用 t 号L型骨牌覆盖右下角,再递归处理子棋盘
//递归处理子棋盘
else { // 用 t 号L型骨牌覆盖左下角,再递归处理子棋盘
board[tr + s - 1][tc + s] = t;
ChessBoard(tr, tc+s, tr+s-1, tc+s, s); }
// 覆盖左下角子棋盘
if (dr >= tr + s && dc < tc + s) // 特殊方格在左下角子棋盘中
tr:棋盘左上角方格的行号 tc:棋盘左上角方格的列号 dr:特殊方格所在的行号 dc:特殊方格所在的列号 size:方形棋盘的边长
#include <stdio.h>
#define N 16
int a[100][100];
int t=1;
void Tromino(int (*a)[N],int dr,int dc,int tr,int tc,int size)
a[tr+s][tc+s-1]=t;
a[tr+s][tc+s]=t;
t++;
Tromino(a,dr,dc,tr,tc+s,s);
Tromino(a,tr+s-1,tc+s-1,tr,tc,s);
Tromino(a,tr+s,tc+s-1,tr+s,tc,s);
Tromino(a,tr+s,tc+s,tr+s,tc+s,s);
棋盘覆盖问题
在一个2k×2k (k≥0)个方格组成的棋盘中, 恰有一个方格与其他方格不同,称该方格为特殊 方格。
棋盘覆盖问题要求用如图(b)所示的L型骨牌 覆盖给定棋盘上除特殊方格以外的所有方格,且 骨牌之间不得有重叠。
(a) k=2时的一种棋盘
(b) 4种不同形状的L型骨牌
分治策略
• 技巧在于划分棋盘,使每个子棋盘均包含一 个特殊方格,从而将原问题分解为规模较小的 棋盘覆盖问题
(2)子棋盘:在棋盘数组board[size][size]中, 由子棋盘左上角的下标tr、tc和棋盘边长s表示;
(3)特殊方格:用board[dr][dc]表示,dr和dc是 该特殊方格在棋盘数组board中的下标;
(4) L型骨牌:一个2k×2k的棋盘中有一个特殊 方格,所以,用到L型骨牌的个数为(4k-1)/3,将所 有L型骨牌从1开始连续编号,用一个全局变量t表 示
t++;
Tromino(a,dr,dc,tr+s,tc+s,s);
Tromino(a,tr+s,tc+s-1,tr+s,tc,s);
Tromino(a,tr+s-1,tc+s-1,tr,tc,s);
Tromino(a,tr+s-1,tc+s,tr,tc+s,s);
}
}
}
main() {
int i,j,dr,dc, a[N][N]; printf("please input dr(0<dr<%d):",N); scanf("%d",&dr); printf("please input dc(0<dc<%d):",N); scanf("%d",&dc); a[dr][dc]=0; Tromino(a,dr,dc,0,0,N); for(i=0;i<N;i++) {
相关文档
最新文档