分治算法-残缺棋盘

分治算法-残缺棋盘

 残缺棋盘是一个2^k*2^个方格的棋盘,其中恰有1个方格残缺。图中给出,其中残缺部分用阴影表示。


这样的棋盘称为"三格板",残缺棋盘问题就是用这四种三格板覆盖更大的残缺棋盘。再次覆盖中要求:

(1)两个三格板不能重复。

(2)三格板不能覆盖残缺棋盘方格,但必须覆盖到其他所有的方格。

算法思路:

利用分治算法将棋盘细化,逐步解决,以4*4为例


首先判断残缺的位置在哪里,然后在中间填上对应的三格板,如在上图中间拼上三角板(4),变成下面这样


然后通过中间将其分成了4个2*2的小残缺棋盘,从而问题得以解决


4*4的分析过于简单,现在我们以8*8为例进行分析,能更清楚的理解这个例子中分治算法的思想


首先将三格板放置在中间,将其分4个小的4*4的残缺棋盘


通过红色线将其划分成4个4*4的残缺棋盘,现在以左上的残缺棋盘为例

然后将左的4*4的小棋盘右划分成了4个2*2的小棋盘,这样就将问题优化成了2*2的三角棋盘的小问题,这样很快就能将左上的4*4的残缺棋盘解决了

下面继续分析右上的4*4的棋盘,根据残缺的方格在小棋盘中的位置,在中间选择合适的三格板将小的残缺棋盘继续划分,将问题分化成更小的状态


接着的问题和上面一样分析。右上角的小棋盘很快也能解决了,下面两块残缺棋盘的分析方法和上面的一样,整个问题就这样一步步的分解成小问题,然后解决了。

下面是源代码


 
 
  1. #include <iostream>
  2. using namespace std;
  3. int amount,Board[ 100][ 100];
  4. void Cover(int tr,int tc,int dr,int dc,int size)
  5. {
  6. int s,t;
  7. if(size< 2)
  8. return ;
  9. amount++;
  10. t=amount;
  11. s=size/ 2;
  12. if(dr<tr+s&&dc<tc+s) //残缺在左上角
  13. {
  14. //覆盖中间位置
  15. Board[tr+s -1][tc+s]=t;
  16. Board[tr+s][tc+s -1]=t;
  17. Board[tr+s][tc+s]=t;
  18. Cover(tr,tc,dr,dc,s); //覆盖左上
  19. Cover(tr,tc+s,tr+s -1,tc+s,s); //覆盖右上
  20. Cover(tr+s,tc,tr+s,tc+s -1,s); //覆盖左下
  21. Cover(tr+s,tc+s,tr+s,tc+s,s); //覆盖右下
  22. }
  23. else if(dr<tr+s&&dc>=tc+s) //残缺在右上角
  24. {
  25. Board[tr+s -1][tc+s -1]=t;
  26. Board[tr+s][tc+s -1]=t;
  27. Board[tr+s][tc+s]=t;
  28. Cover(tr,tc,tr+s -1,tc+s -1,s);
  29. Cover(tr,tc+s,dr,dc,s);
  30. Cover(tr+s,tc,tr+s,tc+s -1,s);
  31. Cover(tr+s,tc+s,tr+s,tc+s,s);
  32. }
  33. else if(dr>=tr+s&&dc<tc+s) //残缺在左下
  34. {
  35. Board[tr+s -1][tc+s -1]=t;
  36. Board[tr+s -1][tc+s]=t;
  37. Board[tr+s][tc+s]=t;
  38. Cover(tr,tc,tr+s -1,tc+s -1,s);
  39. Cover(tr,tc+s,tr+s -1,tc+s,s);
  40. Cover(tr+s,tc,dr,dc,s);
  41. Cover(tr+s,tc+s,tr+s,tc+s,s);
  42. }
  43. else
  44. {
  45. Board[tr+s -1][tc+s -1]=t;
  46. Board[tr+s -1][tc+s]=t;
  47. Board[tr+s][tc+s -1]=t;
  48. Cover(tr,tc,tr+s -1,tc+s -1,s);
  49. Cover(tr,tc+s,tr+s -1,tc+s,s);
  50. Cover(tr+s,tc,tr+s,tc+s -1,s);
  51. Cover(tr+s,tc+s,dr,dc,s);
  52. }
  53. }
  54. void Print(int s)
  55. {
  56. for( int i= 1;i<=s;i++)
  57. {
  58. for( int j= 1;j<=s;j++)
  59. printf( "%5d ",Board[i][j]);
  60. printf( "\n");
  61. }
  62. }
  63. int main()
  64. {
  65. int s= 1,k,x,y;
  66. printf( "输入2残缺棋盘的规模:2^k,k=");
  67. scanf( "%d",&k);
  68. for( int i= 1;i<=k;i++)
  69. s*= 2;
  70. printf( "输入棋盘残缺位置(x,y):");
  71. scanf( "%d%d",&x,&y);
  72. Board[x][y]= 0;
  73. Cover( 1, 1,x,y,s);
  74. Print(s);
  75. return 0;
  76. }




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

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

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

    请填写红包祝福语或标题

    红包个数最小为10个

    红包金额最低5元

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

    抵扣说明:

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

    余额充值