完全覆盖问题

一问题分析

将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)为在n列时的覆盖方案数目,f(0)=1f(0)=1f(0)=1,f(2)我们以两列为一个单位,他与f ( 0 )的排列总数有关,而f ( 2 ) = 3 是0号位置的排列数目之和*[1-2]位置的排列方法数目,因此初始化为1.

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

图Ⅰ 1

图Ⅱ 1

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

算法流程图1

代码如下

#include <iostream>

using namespace std;

int m,n;

bool **Chess;

int Count=0;

void Domino(int i,int j){

if(i==m){Count++;return;}

if(j==n-1){

if(Chess[i][j]==0){

if(i!=m-1&&Chess[i+1][j]==0){

Chess[i][j]=Chess[i+1][j]=1;

Domino(i+1,0);

Chess[i][j]=Chess[i+1][j]=0;

}

}

else Domino(i+1,0);

}

else{

if(Chess[i][j]==0){

if(i!=m-1&&Chess[i+1][j]==0){

Chess[i][j]=Chess[i+1][j]=1;

Domino(i,j+1);

Chess[i][j]=Chess[i+1][j]=0;

}

if(Chess[i][j+1]==0){

Chess[i][j]=Chess[i][j+1]=1;

Domino(i,j+1);

Chess[i][j]=Chess[i][j+1]=0;

}

}

else Domino(i,j+1);

}

}

int main(){

cin >> m >> n;

bool *p=new bool[m*n];

for(int i=0;i<m*n;i++)p[i]=0;

Chess=new bool*[m];

for(int i=0;i<m;i++)Chess[i]=p+i*n;

Domino(0,0);

cout << Count << endl;

delete []Chess;

delete []p;

return 0;

}

  • 3
    点赞
  • 3
    收藏
    觉得还不错? 一键收藏
  • 2
    评论
棋盘覆盖问题是指在一个大小为2^n * 2^n的正方形棋盘中,有一个方格被去掉(如下图所示),现在需要用L型骨牌(类似于多米诺骨牌,由两个小正方形组成,形状如“L”)将棋盘完全覆盖,求覆盖方案。 ![棋盘覆盖问题示意图](https://img-blog.csdn.net/20150923193807438) MFC是微软基于Windows API的一个应用框架,用于快速开发Windows桌面应用程序。实现棋盘覆盖问题需要使用递归算法,MFC可以很方便地实现递归算法,以下是一个简单的MFC程序实现棋盘覆盖问题: 1. 创建一个MFC应用程序,选择对话框为基础模板。 2. 在对话框中添加一个按钮,用于触发覆盖棋盘的操作。 3. 在对话框类的头文件中添加以下代码: ```cpp #define MAXN 1024 // 棋盘大小的最大值 int board[MAXN][MAXN]; // 棋盘 int tile = 1; // 骨牌编号 ``` 4. 在对话框类的.cpp文件中添加以下代码: ```cpp // 将区域(x1, y1)~(x2, y2)覆盖成L型骨牌,除了(r, c)这个位置 void cover(int x1, int y1, int x2, int y2, int r, int c) { if (x1 == x2 && y1 == y2) return; // 区域大小为1,不需要覆盖 int s = tile++; // 当前使用的骨牌编号 int xm = (x1 + x2) / 2, ym = (y1 + y2) / 2; // 中心点坐标 // 覆盖左上角区域 if (r <= xm && c <= ym) cover(x1, y1, xm, ym, r, c); else { board[xm][ym] = s; // 覆盖其余三个区域 cover(x1, y1, xm, ym, xm, ym); if (r <= xm && c > ym) cover(x1, ym + 1, xm, y2, r, c); if (r > xm && c <= ym) cover(xm + 1, y1, x2, ym, r, c); if (r > xm && c > ym) cover(xm + 1, ym + 1, x2, y2, r, c); } // 覆盖右上角区域 if (r <= xm && c > ym) cover(x1, ym + 1, xm, y2, r, c); else { board[xm][ym + 1] = s; // 覆盖其余三个区域 if (r <= xm && c <= ym) cover(x1, y1, xm, ym, xm, ym); cover(x1, ym + 1, xm, y2, xm, ym + 1); if (r > xm && c <= ym) cover(xm + 1, y1, x2, ym, r, c); if (r > xm && c > ym) cover(xm + 1, ym + 1, x2, y2, r, c); } // 覆盖左下角区域 if (r > xm && c <= ym) cover(xm + 1, y1, x2, ym, r, c); else { board[xm + 1][ym] = s; // 覆盖其余三个区域 if (r <= xm && c <= ym) cover(x1, y1, xm, ym, xm + 1, ym); if (r <= xm && c > ym) cover(x1, ym + 1, xm, y2, xm + 1, ym); cover(xm + 1, y1, x2, ym, xm + 1, ym); if (r > xm && c > ym) cover(xm + 1, ym + 1, x2, y2, r, c); } // 覆盖右下角区域 if (r > xm && c > ym) cover(xm + 1, ym + 1, x2, y2, r, c); else { board[xm + 1][ym + 1] = s; // 覆盖其余三个区域 if (r <= xm && c <= ym) cover(x1, y1, xm, ym, xm + 1, ym + 1); if (r <= xm && c > ym) cover(x1, ym + 1, xm, y2, xm + 1, ym + 1); if (r > xm && c <= ym) cover(xm + 1, y1, x2, ym, xm + 1, ym + 1); cover(xm + 1, ym + 1, x2, y2, xm + 1, ym + 1); } } // 初始化棋盘 void init_board(int n, int r, int c) { memset(board, -1, sizeof(board)); board[r][c] = 0; // 空白位置 tile = 1; } // 绘制棋盘 void draw_board(CDC* pDC, int n, int x, int y, int w) { for (int i = 0; i < n; i++) { for (int j = 0; j < n; j++) { if (board[i][j] == -1) pDC->FillSolidRect(x + j * w, y + i * w, w, w, RGB(255, 255, 255)); // 白色 else if (board[i][j] == 0) pDC->FillSolidRect(x + j * w, y + i * w, w, w, RGB(0, 0, 0)); // 黑色 else pDC->FillSolidRect(x + j * w, y + i * w, w, w, RGB(255, 0, 0)); // 其他颜色 } } } // 覆盖棋盘 void cover_board(int n, int r, int c) { init_board(n, r, c); cover(0, 0, n - 1, n - 1, r, c); } // 棋盘覆盖操作 void CMyDlg::OnBnClickedButton1() { int n = 8; // 棋盘大小 int r = rand() % n, c = rand() % n; // 随机取一个空白位置 cover_board(n, r, c); // 覆盖棋盘 CClientDC dc(this); draw_board(&dc, n, 10, 50, 30); // 绘制棋盘 } ``` 在上述代码中,`cover()`函数使用递归算法实现棋盘的覆盖,`init_board()`函数用于初始化棋盘,`draw_board()`函数用于绘制棋盘。在点击按钮时,调用`cover_board()`函数进行棋盘覆盖,然后调用`draw_board()`函数绘制棋盘。运行程序后,每次点击按钮都会生成一个随机的空白位置,并用L型骨牌覆盖棋盘。

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值