棋盘覆盖(分治)
一、实验内容
运用递归与分治策略解决棋盘覆盖问题(循环赛日程表)
使用递归与分治策略解决棋盘覆盖问题。
二、所用算法基本思想及复杂度分析
1.算法基本思想
递归:直接或间接地调用自身的算法称为递归算法。
分治:将要求解的较大规模的问题分割成k个更小规模的子问题,对这k个子问题分别求解。如果子问题的规模仍然不够小,则再划分为k个子问题,如此递归的进行下去,直到问题规模足够小,很容易求出其解为止;然后将求出的小规模的问题的解合并为一个更大规模的问题的解,自底向上逐步求出原来问题的解。
2.问题分析及算法设计
问题分析:
(1)对于棋盘覆盖问题,首先我们需要先把棋盘等分成四个正方形分别是:左上、左下、右上、右下,四个子棋盘。
(2)对于每一个子棋盘,如果其存在特殊方格,将它再分成四个子棋盘,并且使用同样的方法,对子棋盘进行递归。
(3)对于不存在特殊方格的子棋盘,假定与另外三个子棋盘相接的为特殊方格,有了特殊方格之后,对这个子棋盘进行递归。
(4)直到子棋盘为1*1的正方形。
算法设计:
(1)棋盘:可以用一个二维数组a[size][size]表示一个棋盘,其中,size=2^k。为了在递归处理的过程中使用同一个棋盘,将数组a设为全局变量。
(2)子棋盘:整个棋盘用二维数组a[size][size]表示,其中的子棋盘由棋盘左上角的下标tr、tc和棋盘大小size表示。
(3)特殊方格:用a[dr][dc]表示特殊方格,dr和dc是该特殊方格在二维数组a中的下标。
(4)L型骨牌:一个2k×2k的棋盘中有一个特殊方格,所以,用到L型骨牌的个数为(4^k-1)/3,将所有L型骨牌从1开始连续编号,用一个全局变量t表示。
(5)特例:
3.算法复杂度分析
三、源程序核心代码及注释(截图)
四、运行结果
五、调试和运行程序过程中产生的问题及解决方法,实验总结(5行以上)
调试过程中,设置监视比较麻烦,如果不一个个列举出来,很难对应所得到的值,就是比较容易看错,此时应该结合输出的棋盘上的值一个个去看,也就会发现其大致规律。对于这次实验,让我懂得了分治法的精髓,分—将问题分解成规模变小的问题;治—将这些小问题一个个去解决;最终形成一个“合”,就是将所有的子问题的答案合起来,形成最终要解决的答案。概念说起来简单,但实践起来难度就大了,所以需要多加练习,才能更好的掌握。
#include<iostream>
#include<stdio.h>
#include<stdlib.h>
#include<string.h>
using namespace std;
int L = 1;//先定义L形骨牌的最初编号
int a[50][50];//表示棋牌的最大程度
//tr,tc表示棋盘的起始位置(第tr行,第tc列)
//dr,dc表示特殊格子所在的位置
//size表示棋盘大小,k*k的棋盘,size为k
//定义二分法划分后的棋盘
void ChessBoard(int tr, int tc, int dr, int dc, int size) {
if (size == 1)
{
return;//当只有一个格子时,直接是递归的出口
}
int s = size / 2;//使用二分法将其划分成4份
int l = L++;//骨牌的递增数值
//假设特殊点的位置在左上
if (dr < tr + s && dc < tc + s) {
ChessBoard(tr, tc, dr, dc, s);
}
else {//如果不在就填充二分后左上部分的右下角的格子进行填充
a[tr + s - 1][tc + s - 1] = 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 {//如果不在就填充二分后右上部分的左下角的格子进行填充
a[tr + s - 1][tc + s] = 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 {//如果不在就填充二分后左下部分的右上角的格子进行填充
a[tr + s][tc + s - 1] = 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 {//如果不在就填充二分后右下部分的左上角的格子进行填充
a[tr + s][tc + s] = l;
ChessBoard(tr + s, tc + s, tr + s, tc + s, s);
}
}
int main()
{
int size, i, j;
cout << "棋盘的大小:";
cin >> size;//输入棋盘的大小
//数组的初始化
for (i = 0; i < size; i++) {
for (j = 0; j < size; j++) {
a[i][j] = 0;
}
}
int x, y;
cout << "特殊点的位置:";
cin >> x >> y;//输入特殊点的位置
ChessBoard(0, 0, x, y, size);
//输出棋盘
for (i = 0; i < size; i++) {
for (j = 0; j < size; j++) {
printf("%-2d ", a[i][j]);
}
cout << endl;
}
return 0;
}