分而治之算法---残缺棋盘

小打小闹也是福

小打小闹也是福

2016-02-19 13:06

想要天天向上,就要懂得享受学习。图老师为大家推荐分而治之算法---残缺棋盘,精彩的内容需要你们用心的阅读。还在等什么快点来看看吧!
残缺棋盘(defective chessboard)是一个有2k×2k 个方格的棋盘,其中恰有一个方格残缺。图2 - 3给出k≤2时各种可能的残缺棋盘,其中残缺的方格用阴影表示。注重当k= 0时,仅存在一种可能的残缺棋盘(如图1 4 - 3 a所示)。事实上,对于任意k,恰好存在22k 种不同的残缺棋盘。
  
  残缺棋盘的问题要求用三格板(t r i o m i n o e s)覆盖残缺棋盘(如图1 4 - 4所示)。在此覆盖中,两个三格板不能重叠,三格板不能覆盖残缺方格,但必须覆盖其他所有的方格。在这种限制条件下,所需要的三格板总数为( 22k -1 ) / 3。可以验证( 22k -1 ) / 3是一个整数。k 为0的残缺棋盘很轻易被覆盖,因为它没有非残缺的方格,用于覆盖的三格板的数目为0。当k= 1时,正好存在3个非残缺的方格,并且这三个方格可用图1 4 - 4中的某一方向的三格板来覆盖。
  
  用分而治之方法可以很好地解决残缺棋盘问题。这一方法可将覆盖2k×2k 残缺棋盘的问题转化为覆盖较小残缺棋盘的问题。2k×2k 棋盘一个很自然的划分方法就是将它划分为如图1 4 - 5 a所示的4个2k - 1×2k - 1 棋盘。注重到当完成这种划分后, 4个小棋盘中仅仅有一个棋盘存在残缺方格(因为原来的2k×2k 棋盘仅仅有一个残缺方格)。首先覆盖其中包含残缺方格的2k - 1×2k - 1 残缺棋盘,然后把剩下的3个小棋盘转变为残缺棋盘,为此将一个三格板放在由这3个小棋盘形成的角上,如图14-5b 所示,其中原2k×2k 棋盘中的残缺方格落入左上角的2k - 1×2k - 1 棋盘。可以采用这种分割技术递归地覆盖2k×2k 残缺棋盘。当棋盘的大小减为1×1时,递归过程终止。此时1×1的棋盘中仅仅包含一个方格且此方格残缺,所以无需放置三格板。
  
  可以将上述分而治之算法编写成一个递归的C++ 函数Ti l e B o a r d (见程序1 4 - 2 )。该函数定义了一个全局的二维整数数组变量B o a r d来表示棋盘。B o a r d [ 0 ] [ 0 ]表示棋盘中左上角的方格。该函数还定义了一个全局整数变量t i l e,其初始值为0。函数的输入参数如下:
  
  ? tr 棋盘中左上角方格所在行。
  
  ? tc 棋盘中左上角方格所在列。
  
  ? dr 残缺方块所在行。
  
  ? dl 残缺方块所在列。
  
  ? size 棋盘的行数或列数。
  
  Ti l e B o a r d函数的调用格式为Ti l e B o a r d(0,0, dr, dc,size),其中s i z e = 2k。覆盖残缺棋盘所需要的三格板数目为( s i z e2 -1 ) / 3。函数TileBoard 用整数1到( s i z e2-1 ) / 3来表示这些三格板,并用三格板的标号来标记被该三格板覆盖的非残缺方格。
  
  令t (k) 为函数Ti l e B o a r d覆盖一个2k×2k 残缺棋盘所需要的时间。当k= 0时,s i z e等于1,覆盖它将花费常数时间d。当k 0时,将进行4次递归的函数调用,这些调用需花费的时间为4t (k-1 )。除了这些时间外, if 条件测试和覆盖3个非残缺方格也需要时间,假设用常数c 表示这些额外时间。可以得到以下递归表达式:
  
  程序14-2 覆盖残缺棋盘
  
  void TileBoard(int tr, int tc, int dr, int dc, int size)
  
  {// 覆盖残缺棋盘
  
  if (size == 1) return;
  
  int t = tile++, // 所使用的三格板的数目
  
  s = size/2; // 象限大小
  
  / /覆盖左上象限
  
  if (dr tr + s && dc tc + s)
  
  // 残缺方格位于本象限
  
  Ti l e B o a r d ( t r, tc, dr, dc, s);
  
  else {// 本象限中没有残缺方格
  
  // 把三格板t 放在右下角
  
  Board[tr + s - 1][tc + s - 1] = t;
  
  // 覆盖其余部分
  
  Ti l e B o a r d ( t r, tc, tr+s-1, tc+s-1, s);}
  
  / /覆盖右上象限
  
  if (dr tr + s && dc = tc + s)
  
  // 残缺方格位于本象限
  
  Ti l e B o a r d ( t r, tc+s, dr, dc, s);
  
  else {// 本象限中没有残缺方格
  
  // 把三格板t 放在左下角
  
  Board[tr + s - 1][tc + s] = t;
  
  // 覆盖其余部分
  
  Ti l e B o a r d ( t r, tc+s, tr+s-1, tc+s, s);}
  
  / /覆盖左下象限
  
  if (dr = tr + s && dc tc + s)
  
  // 残缺方格位于本象限
  
  TileBoard(tr+s, tc, dr, dc, s);
  
  else {// 把三格板t 放在右上角
  
  
  Board[tr + s][tc + s - 1] = t;
  
  // 覆盖其余部分
  
  TileBoard(tr+s, tc, tr+s, tc+s-1, s);}
  
  // 覆盖右下象限
  
  if (dr = tr + s && dc = tc + s)
  
  // 残缺方格位于本象限
  
  TileBoard(tr+s, tc+s, dr, dc, s);
  
  else {// 把三格板t 放在左上角
  
  Board[tr + s][tc + s] = t;
  
  // 覆盖其余部分
  
  TileBoard(tr+s, tc+s, tr+s, tc+s, s);}
  
  }
  
  void OutputBoard(int size)
  
  {
  
  for (int i = 0; i size; i++) {
  
  for (int j = 0; j size; j++)
  
  cout setw (5) Board[i][j];
  
  cout endl;
  
  }
  
  }
  
  可以用迭代的方法来计算这个表达式(见例2 - 2 0),可得t (k )= ( 4k )= (所需的三格板的数目)。由于必须花费至少( 1 )的时间来放置每一块三格表,因此不可能得到一个比分而治之算法更快的算法。
展开更多 50%)
分享

猜你喜欢

分而治之算法---残缺棋盘

编程语言 网络编程
分而治之算法---残缺棋盘

马走日棋盘算法

C语言教程 C语言函数
马走日棋盘算法

s8lol主宰符文怎么配

英雄联盟 网络游戏
s8lol主宰符文怎么配

最正宗棋盘饼干的做法 棋盘饼干如何做

黄油 鸡蛋
最正宗棋盘饼干的做法 棋盘饼干如何做

棋盘饼干吃法

黄油 鸡蛋 烘焙
棋盘饼干吃法

lol偷钱流符文搭配推荐

英雄联盟 网络游戏
lol偷钱流符文搭配推荐

【算法】扑克发牌算法实现

Web开发
【算法】扑克发牌算法实现

如何做棋盘饼干 怎样做棋盘饼干

黄油 鸡蛋
如何做棋盘饼干 怎样做棋盘饼干

lolAD刺客新符文搭配推荐

英雄联盟
lolAD刺客新符文搭配推荐

jquery validate.js表单验证的基本用法入门

jquery validate.js表单验证的基本用法入门

制作出多彩的Excel2007单元格数据

制作出多彩的Excel2007单元格数据
下拉加载更多内容 ↓