残缺棋盘问题



残缺棋盘问题


对于1*1 2*2 4*4 8*8等 2^k*2^k的棋盘来说,都存在一个任意的位置,而在棋盘剩余位置都可以用一个或多个由三个格子组成的L型直角版覆盖
那么如何覆盖呢?
在这里 采用分而治之的方法来考虑。
对于已知的残缺位置,一定处于当前棋盘的某个象限,那么在剩下的三个象限中在连接的地方各取一个方块为残缺,这三个方块的位置刚好可以构成
一个L型直角,而对于每个象限而言又是规定了一个残缺位置,这样与初始状态又一致了。也就是说,将一个完整的棋盘不断地化为四份,并
且补充每个象限中的残缺位置,直到不能再划分。利用递归来实现。

代码如下:


#include<iostream>
#include<string>
#include<stdlib.h>
#include <iomanip>

using namespace std;


//递归实现残缺棋盘
int tag = 0;


void  function(int tr, int tc, int dr, int dc, int size,int **target);// (tr,tc)表示该棋盘的最左上角的方格的坐标。 (dr,dc)表示残缺方格的位置坐标 size表示棋盘的行列数 target是用来

//存放L型直角编码的。 位置从(0,0)开始计算

int main()
{
 int size =16;
 int **target = new int*[size];
 //把相应的二维数组初始化 全都初始化为0
 for (int i = 0; i < size; i++)
 {
  target[i] = new int[size];
  for (int j = 0; j < size; j++)
   target[i][j] = 0;
 }

 function(0, 0, 3, 3, size, target);

 //输出这个数组
 for (int i = 0; i < size; i++)
 {
  for (int j = 0; j < size; j++)
  {
   cout <<setw(2)<< target[i][j] << "  ";
  }
  cout << endl;
 }

 system("pause");

 //删除这个二维数组
 for (int i = 0; i < size; i++)
 {
  delete[] target[i];
 }
 delete[] target;
 target = 0;

 return 0;
}

void  function(int tr, int tc, int dr, int dc, int size,int **target)
{
 int s = size / 2;
 int t = ++tag;
 if (s == 0)
  return;//当size==1时不再继续递归,返回上一层。

 //讨论缺陷在左上角的情况
 if ((tr+s) > dr && (tc+s) > dc)
 {
  //本身所在的小棋盘保持不变
  function(tr, tc, dr, dc, s, target);
  //将右上角的棋盘的左下角的格子置为缺陷,并且用t来标记
  target[tr + s - 1][tc + s] = t;
  function(tr, tc + s, tr + s - 1, tc + s, s, target);

  //将左下角棋盘的右上角的格子置为缺陷,并且标记。
  target[tr + s][tc + s - 1] = t;
  function(tr + s, tc, tr + s, tr + s - 1, s, target);

  //将右下角棋盘的左上角的格子置为缺陷,并且标记
  target[tr + s][tc + s] = t;
  function(tr + s, tc + s, tr + s, tc + s, s, target);

 }
 //讨论缺陷在右上角的情况 与第一种情况相似 模仿着来写
 //void  function(int tr, int tc, int dr, int dc, int size,int **target)
 else if ((tr+s) > dr &&(tc+s) <= dc)
 {
  target[tr + s - 1][tc + s - 1] = t;
  function(tr, tc, tr + s - 1, tr + s - 1, s, target);

  function(tr, tc + s, dr, dc, s, target);

  target[tr + s][tc + s - 1] = t;
  function(tr + s, tc, tr + s, tc + s - 1, s, target);

  target[tr + s][tc + s] = t;
  function(tr + s, tc + s, tr + s, tc + s, s, target);

 }
 //缺陷在左下角的情况
 else if ((tr+s) <= dr &&(tc+s) > dc)
 {
  target[tr+s-1][tc+s-1] = t;
  function(tr, tc, tr + s - 1, tc + s - 1, s, target);

  target[tr+s-1][tc+s] = t;
  function(tr, tc + s, tr + s - 1, tc + s, s, target);

  function(tr + s, tc, dr, dc, s, target);

  target[tr+s][tc+s] = t;
  function(tr + s, tc + s, tr + s, tc + s, s, target);
 }

 //缺陷在右下角的时候
 else 
 {
  target[tr + s - 1][tc + s - 1] = t;
  function(tr, tc, tr + s - 1, tc + s - 1, s, target);

  target[tr + s - 1][tc + s] = t;
  function(tr, tc + s, tr + s - 1, tc + s, s, target);

  target[tr + s][tc + s - 1] = t;
  function(tr + s, tc, tr + s, tc + s - 1, s, target);

  function(tr + s, tc + s, dr, dc, s, target);
 }

}

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值