完美覆盖问题回溯法求解

问题描述

用2×1或1×2的骨牌把m×n的棋盘完全覆盖是一个很容易解决的问题。那么,能不能把完全覆盖的种数求出来会不会很复杂呢?请给出所有各不相同覆盖方案。

棋盘的完美覆盖又称多米诺覆盖(Domino Tiling),是组合数学中一个颇有趣味的问题。首先介绍与该问题相关的一些基本概念:

多米诺(Domino):一个多米诺是由两个单位正方形拼接而成的 1\times2 或 2\times1 矩形。

多米诺覆盖(Domino Tiling): 如果一些多米诺恰好互不重叠地覆盖一个 m\times n 棋盘,则此覆盖称为一个多米诺覆盖。



作者:心露边白
链接:https://www.jianshu.com/p/14dbb6121ac3
来源:简书
著作权归作者所有。商业转载请联系作者获得授权,非商业转载请注明出处。

要求

给定任意m行n列的棋盘,编写程序求出使用2×1或1×2的骨牌对棋盘进行完全覆盖有多少种不同的方法。

解题思路

采用回溯法从左上角至右下角依次扫描未放置骨牌的方格,根据方格的右方和下方是否已经放置了骨牌来判断放置骨牌的位置以达到求解的目的。

在存储方面,用 bool A[m][n] 存储 m\times n 棋盘,每一次加入新的多米诺时,就将相邻的一对小方格上的 bool 值设置为 1 (表示占用)。

以3x4棋盘为例

 

 

 

 

 

此时填满棋盘,计数+1并进行回溯

 

 

 代码如下

#include <iostream>
using namespace std;
int m,n; // 长宽
bool **Chess; // 棋盘(使用bool型,前面的两个**表示定义了一个二维的bool型数组)
int Count=0; // 计数 
void Domino(int i,int j){
    if(i==m){
    	puts("______________");
		for(int i=0;i<m;++i)
		{
			for(int j=0;j<n;++j){
				cout<<Chess[i][j]<<" ";
			}
			puts("");
		}
		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;
		cout<<Chess[i]<<endl;
	}
	puts("______________");
	for(int i=0;i<m;++i)
	{
		for(int j=0;j<n;++j){
			cout<<&Chess[i][j]<<" ";
		}
		puts("");
	}
	puts("______________");
    Domino(0,0);
    cout<<endl; 
    cout<<Count<<endl;
    return 0;
}

代码运行结果

其中—————

        —————内的地址为提前为执行算法占用的空间。

  • 1
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 2
    评论
评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值