棋盘覆盖问题


问题描述

1、在一个2k×2k个方格组成的棋盘中,恰有一个方格与其他方格不同,称该方格为一特殊方格,且称该棋盘为特殊棋盘。
如下为一个k=2的棋盘,其有2k×2k=4×4=16个不同的特殊棋盘
2、要使用图示所示的4种不同形态的L型骨牌覆盖给定的特殊棋盘上除特殊方格以外的所有方格,且任何2个L型骨牌不得重叠覆盖

在这里插入图片描述
例如,很容易得出在2k×2k个方格组成的特殊棋盘中,需要用(2k×2k-1)/3=(4k-1)/3个L型骨牌
在这里插入图片描述

问题分析

k=0时,有一种覆盖方案
k>0时,采用分治策略,将2k×2k,分割成4个2k-1×2k-1个子棋盘,而特殊方格位于其中一个子棋盘,其余的子棋盘无特殊方格; 为了将这三个无特殊方格的子棋盘转化为特殊棋盘,可用一个L型骨牌覆盖这3个子棋盘的汇合处,从而将原问题转化为4个较小规模的棋盘覆盖问题,递归得调用这种分割,直到棋盘简化为1×1的棋盘

在这里插入图片描述


算法分析

1、大棋盘:使用二维数组board[size][size]来表示这个2k×2k的棋盘,其中size=2k
2、子棋盘:子棋盘左上角下标位置tr、tc、棋盘大小s
3、特殊方格:board[dr][dc]表示,dr、dc均为特殊方格在二维数组board里面的下标
4、L型骨牌:L型骨牌在2k×2k的特殊棋盘中,所填充所需要的个数为(4k-1)/3个,对骨牌需要编号确认个数,因此需要全局变量t


代码实现

/*
   author:monkey
   time:2020-3-26
*/
#include <stdio.h>
int chess[10][10];
int num; //L型骨牌编号
/*
  tr、tc:子棋盘左上角的位置(行/列)
  dr、dc:特殊方格的位置(行/列)
  size:2^k^
*/
void chessBoard(int tr,int tc,int dr,int dc,int size){
    if(size == 1) return;
    int s = size/2;//分割棋盘成(2^k-1^)×(2^k-1^)的棋盘
    int t = ++num;//L型骨牌自增
    
     //当特殊方格位于左上角子棋盘
    if(dr < tr + s&&dc < tc + s){
       chessBoard(tr,tc,dr,dc,s);//有则递归调用左上子棋盘
    }else{
       chess[tr+s-1][tc+s-1] = 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{
       chess[tr+s-1][tc+s] = 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{
       chess[tr+s][tc+s-1] = 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{
       chess[tr+s][tc+s] = t; //无则用L型骨牌填充右下子棋盘的左上角,将其变成含有特殊方格的特殊棋盘
       chessBoard(tr+s,tc+s,tr+s,tc+s,s);//递归调用右下子棋盘
    }
}
int main(){
	int dr,dc,size;
	while(true){
		printf("请输入棋盘大小以及特殊方格的位置:");
		scanf("%d %d %d",&size,&dr,&dc);
		if(size == 0)
			break;
		//初始化
		chess[dr][dc] = 1;
		num = 1;
		chessBoard(0,0,dr,dc,size);
		printf("填充完后的棋盘显示:\n");
		for(int i = 0;i < size;i++){
			for(int j = 0;j < size;j++){
				printf("%d",chess[i][j]);
				printf(" ");
			}
			printf("\n");
		}
	}
	return 0;
}
package main

import "fmt"
func HuaFen(n int,m int)int{
    if n < 1||m < 1{
        return 0
    }else if n == 1||m == 1 {
        return 1
     }else if n < m {
        return HuaFen(n,n)
     }else if n == m {
        return HuaFen(n,m-1)+1
     }else{
        return HuaFen(n,m-1)+HuaFen(n-m,m)
    }
}
func main() {
	 var num int
	 for {
		 fmt.Print("输入需要划分的数字:")
		 fmt.Scanf("%d",&num)
		 if num == 0{
		 	break
		 }
		 res := HuaFen(num,num)
		 fmt.Printf("数字%d划分的结果有%d种\n",num,res)
	   }
}
  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值