关于算法完全覆盖问题的相关理解以及代码

一问题分析

将1*2型的骨牌填充到m*n的棋盘当中,使其完全覆盖而且任何骨牌不能重叠。将问题缩小成同类型子问题。

二设计思路

先从2*n和3*n的棋盘入手看其然后将其进行对更大的棋盘执行覆盖,再使用排列组合问题进行求解问题。

三算法设计

先分析2*n:数学归纳法

归纳总结图1

2*n的骨牌的填充:

  1. 可以由2*(n-1)的骨牌最后加上一张竖2*1的骨牌,此时的填充方法有F(n-1)种。(2)还可以由2*(n-2)的骨牌最后加上2张横着的2*1的骨牌,此时的填充方法有F(n-2)种。(3)还有一种情况是由2× (n-2)的骨牌最后加上2张竖着的2×1的骨牌。总结得为斐波那契数列

奇数列不能填充,扩大最小项为两列一单位记函数f(n)f(n)f(n)为在n nn列时的覆盖方案数目,f(0)=1f(0)=1f(0)=1,f(2)f(2)f(2)我们以两列为一个单位,他与f ( 0 )的排列总数有关,而f ( 2 ) = 3 是0号位置的排列数目之和*[1-2]位置的排列方法数目,因此初始化为1.

再来看看f(4) f(4)f(4),图Ⅰ。首先考虑他最右边两列有三种情况,承上之前的排列数即f(2)*3f(2)*3f(2)∗3,四列也可能为图Ⅱ,得出f(0)*2f(0)*2f(0)*2。

图Ⅰ 1

图Ⅱ 1

通过递推得出f(n)=3f(n-2)+2f(n-4)+2f(n-6)+...+f(0)

算法流程图1

四代码

#include <iostream>

using namespace std;

const int maxNum = 1 << 10;

// 棋盘

int chess[maxNum][maxNum];

// L型牌编号

int number;

void chessBoard(int row, int column, int x, int y, int siz) {

// 递归出口

if(siz == 1) {

return;

}

// 对半划分成2^(siz - 1) * 2^(siz - 1)的棋盘

int s = siz / 2;

// L型牌编号自增

int t = ++number;

// 中间点,以此判别(x,y)在哪个子棋盘中

int centerRow = row + s;

int centerColumn = column + s;

// 黑色方格在左上子棋盘

if(x < centerRow && y < centerColumn) {

chessBoard(row, column, x, y, s);

} else {

// 不在则填充左上子棋盘的右下角

chess[centerRow - 1][centerColumn - 1] = t;

// 然后覆盖其他格子,注意这时(x,y)要看做已填充位置

chessBoard(row, column, centerRow - 1, centerColumn - 1, s);

}

// 黑色方格在右上子棋盘

if(x < centerRow && y >= centerColumn) {

chessBoard(row, centerColumn, x, y, s);

} else {

// 不在则填充右上子棋盘的左下角

chess[centerRow - 1][centerColumn] = t;

// 然后覆盖其他格子,注意这时(x,y)要看做已填充位置

chessBoard(row, centerColumn, centerRow - 1, centerColumn, s);

}

// 黑色方格在左下子棋盘

if(x >= centerRow && y < centerColumn) {

chessBoard(centerRow, column, x, y, s);

} else {

// 不在则填充左下子棋盘的右上角

chess[centerRow][centerColumn - 1] = t;

// 然后覆盖其他格子,注意这时(x,y)要看做已填充位置

chessBoard(centerRow, column, centerRow, centerColumn - 1, s);

}

// 黑色方格在右下子棋盘

if(x >= centerRow && y >= centerColumn) {

chessBoard(centerRow, centerColumn, x, y, s);

} else {

// 不在则填充右下子棋盘的左上角

chess[centerRow][centerColumn] = t;

// 然后覆盖其他格子,注意这时(x,y)要看做已填充位置

chessBoard(centerRow, centerColumn, centerRow, centerColumn, s);

}

}

int main() {

// 大小,黑色方格位置

int siz, x, y;

while(true) {

cout << "(x,y)从(0,0)开始,输入数据为0 0 0即结束程序。" << endl;

cout << "请输入棋盘大小和黑色方格位置(x,y):";

cin >> siz >> x >> y;

// 退出条件

if(siz == 0) {

break;

}

// 涂黑(x,y),初始化L型牌编号

chess[x][y] = number = 1;

// 分治法填满棋盘

chessBoard(0, 0, x, y, siz);

// 输出该棋盘

for(int i = 0; i < siz; i++) {

for(int j = 0; j < siz; j++) {

cout << chess[i][j] << "\t";

}

cout << endl << endl << endl;

}

}

return 0;

}

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 1
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值