• 残缺棋盘的覆盖问题


    棋盘覆盖问题   

    问题描述:

          在一个2^k×2^k个方格组成的棋盘中,若有一个方格与其他方格不同,则称该方格为一特殊方格,且称该棋盘为一个特殊棋盘.显然特殊方格在棋盘上出现的位置有4^k种情形.因而对任何k≥0,有4^k种不同的特殊棋盘.
         下图–图(1)中的特殊棋盘是当k=3时16个特殊棋盘中的一个:

    图(1)

    题目要求在棋盘覆盖问题中,要用下图-图(2)所示的4种不同形态的L型骨牌覆盖一个给定的特殊棋盘上除特殊方格以外的所有方格,且任何2个L型骨牌不得重叠覆盖.

    图(2)

    题目输入k,输出棋盘覆盖的顺序。覆盖策略可以自己选择。

    分析:

    这个题其实可以有不同的覆盖顺序。比如:(下图中的数字表示依次覆盖的顺序)

        

    策略a                                            策略b                                             策略c

    策略a:

    不停地分割寻找残缺块所在区域,然后在残缺块周围填充第一块(这个时候size=2);然后回溯一层,填充伪残缺块(这个时候size=4);然后对当前size=4的另外三个子棋盘依次填充(含残缺块的子棋盘当然不再填充了。)。
    填充完size==4的棋盘后,回溯到size=8的棋盘(假如存在size=8的棋盘的话呵呵),重复刚才的过程:先填充size=8这个棋盘的伪残缺块,然后填充另外的三个子棋盘。……

    关键代码如下:

    完整代码:

     1 #include<stdio.h>
     2 int count=0,bord[100][100];
     3 //覆盖以(tr,tc)为左上角坐标,宽为size的棋盘。残缺块或伪残缺块坐标为(dr,dc) 
     4 int cover(int tr,int tc,int size,int dr,int dc);
     5 int main()
     6 {
     7     int x,y,k,size=1;
     8     int i,j;
     9     scanf("%d%d%d",&k,&x,&y);
    10     for(i=1;i<=k;i++) size=size*2;//计算2^k 
    11     cover(0,0,size,x,y);//对原始棋盘进行覆盖 
    12     for(i=0;i<size;i++)//输出棋盘的覆盖结果 
    13     {
    14         for(j=0;j<size;j++)
    15         {
    16             printf("%-2d ",bord[i][j]);
    17         }
    18         printf("
    ");
    19     }
    20     return 0;
    21 }
    22 
    23 int cover(int tr,int tc,int size,int dr,int dc)
    24 {
    25     if(size<2) return 0;//假如棋盘分割到不足2*2则直接返回(这时候没办法用模板去覆盖棋盘了) 
    26     int s;
    27     s=size/2;//表示即将被再次分割后的棋盘大小 
    28     if(dr<(tr+s)&&dc<(tc+s))//表示对当前输入的棋盘而言,残缺块在左上角部分的子棋盘 
    29     {
    30         cover(tr,tc,s,dr,dc);//对左上角子棋盘分割 
    31         count++;
    32         bord[tr+s-1][tc+s]=count;//下面三个赋值语句是用①号模板覆盖 
    33         bord[tr+s][tc+s-1]=count;
    34         bord[tr+s][tc+s]=count;
    35         cover(tr,tc+s,s,tr+s-1,tc+s);//对右上角子棋盘分割
    36         cover(tr+s,tc,s,tr+s,tc+s-1);//对左下角子棋盘分割
    37         cover(tr+s,tc+s,s,tr+s,tc+s);//对右下角子棋盘分割
    38     }
    39     else if(dr<(tr+s)&&dc>=(tc+s))//表示对当前输入的棋盘而言,残缺块在右上角部分的子棋盘 
    40     {
    41         cover(tr,tc+s,s,dr,dc);//对右上角子棋盘分割
    42         count++;
    43         bord[tr+s-1][tc+s-1]=count;//下面三个赋值语句是用②号模板覆盖 
    44         bord[tr+s][tc+s-1]=count;
    45         bord[tr+s][tc+s]=count;
    46         cover(tr,tc,s,tr+s-1,tc+s-1);//对左上角子棋盘分割
    47         cover(tr+s,tc,s,tr+s,tc+s-1);//对左下角子棋盘分割
    48         cover(tr+s,tc+s,s,tr+s,tc+s);//对右下角子棋盘分割
    49     }
    50     else if(dr>=(tr+s)&&dc<(tc+s))//表示对当前输入的棋盘而言,残缺块在左下角部分的子棋盘 
    51     {
    52         cover(tr+s,tc,s,dr,dc);
    53         count++;
    54         bord[tr+s-1][tc+s-1]=count;//下面三个赋值语句是用③号模板覆盖 
    55         bord[tr+s-1][tc+s]=count;
    56         bord[tr+s][tc+s]=count;
    57         cover(tr,tc,s,tr+s-1,tc+s-1);
    58         cover(tr,tc+s,s,tr+s-1,tc+s);
    59         cover(tr+s,tc+s,s,tr+s,tc+s);
    60     }
    61     else if(dr>=(tr+s)&&dc>=(tc+s))//表示对当前输入的棋盘而言,残缺块在右下角部分的子棋盘 
    62     {
    63         cover(tr+s,tc+s,s,dr,dc);
    64         count++;
    65         bord[tr+s-1][tc+s-1]=count;//下面三个赋值语句是用④号模板覆盖 
    66         bord[tr+s-1][tc+s]=count;
    67         bord[tr+s][tc+s-1]=count;
    68         cover(tr,tc,s,tr+s-1,tc+s-1);
    69         cover(tr,tc+s,s,tr+s-1,tc+s);
    70         cover(tr+s,tc,s,tr+s,tc+s-1);
    71     }
    72 }

    策略b:

    每一次分割时,在递归进入下一层之前,先填充伪残缺块。(因为这个时候已经根据残缺块坐标推出可以使用哪种模板填充了。)(这个时候size=n/2)
    然后依次处理当前层的四个子棋盘:分割——填充伪残缺块——处理更小的子棋盘。
    整个程序重复该过程,最终完成填充任务。

    关键代码如下:

    完整代码:

     1 #include<stdio.h>
     2 int count=0,bord[100][100];
     3 //覆盖以(tr,tc)为左上角坐标,宽为size的棋盘。残缺块或伪残缺块坐标为(dr,dc) 
     4 int cover(int tr,int tc,int size,int dr,int dc);
     5 int main()
     6 {
     7     int x,y,k,size=1;
     8     int i,j;
     9     scanf("%d%d%d",&k,&x,&y);
    10     for(i=1;i<=k;i++) size=size*2;//计算2^k 
    11     cover(0,0,size,x,y);//对原始棋盘进行覆盖 
    12     for(i=0;i<size;i++)//输出棋盘的覆盖结果 
    13     {
    14         for(j=0;j<size;j++)
    15         {
    16             printf("%-2d ",bord[i][j]);
    17         }
    18         printf("
    ");
    19     }
    20     return 0;
    21 }
    22 
    23 int cover(int tr,int tc,int size,int dr,int dc)
    24 {
    25     if(size<2) return 0;//假如棋盘分割到不足2*2则直接返回(这时候没办法用模板去覆盖棋盘了) 
    26     int s;
    27     s=size/2;//表示即将被再次分割后的棋盘大小 
    28     if(dr<(tr+s)&&dc<(tc+s))//表示对当前输入的棋盘而言,残缺块在左上角部分的子棋盘 
    29     {
    30         count++;
    31         bord[tr+s-1][tc+s]=count;//下面三个赋值语句是用①号模板覆盖 
    32         bord[tr+s][tc+s-1]=count;
    33         bord[tr+s][tc+s]=count;
    34         cover(tr,tc,s,dr,dc);//对左上角子棋盘分割 
    35         
    36         cover(tr,tc+s,s,tr+s-1,tc+s);//对右上角子棋盘分割
    37         cover(tr+s,tc,s,tr+s,tc+s-1);//对左下角子棋盘分割
    38         cover(tr+s,tc+s,s,tr+s,tc+s);//对右下角子棋盘分割
    39     }
    40     else if(dr<(tr+s)&&dc>=(tc+s))//表示对当前输入的棋盘而言,残缺块在右上角部分的子棋盘 
    41     {
    42         count++;
    43         bord[tr+s-1][tc+s-1]=count;//下面三个赋值语句是用②号模板覆盖 
    44         bord[tr+s][tc+s-1]=count;
    45         bord[tr+s][tc+s]=count;
    46         cover(tr,tc+s,s,dr,dc);//对右上角子棋盘分割
    47         
    48         cover(tr,tc,s,tr+s-1,tc+s-1);//对左上角子棋盘分割
    49         cover(tr+s,tc,s,tr+s,tc+s-1);//对左下角子棋盘分割
    50         cover(tr+s,tc+s,s,tr+s,tc+s);//对右下角子棋盘分割
    51     }
    52     else if(dr>=(tr+s)&&dc<(tc+s))//表示对当前输入的棋盘而言,残缺块在左下角部分的子棋盘 
    53     {
    54         count++;
    55         bord[tr+s-1][tc+s-1]=count;//下面三个赋值语句是用③号模板覆盖 
    56         bord[tr+s-1][tc+s]=count;
    57         bord[tr+s][tc+s]=count;
    58         cover(tr+s,tc,s,dr,dc);
    59         
    60         cover(tr,tc,s,tr+s-1,tc+s-1);
    61         cover(tr,tc+s,s,tr+s-1,tc+s);
    62         cover(tr+s,tc+s,s,tr+s,tc+s);
    63     }
    64     else if(dr>=(tr+s)&&dc>=(tc+s))//表示对当前输入的棋盘而言,残缺块在右下角部分的子棋盘 
    65     {
    66         count++;
    67         bord[tr+s-1][tc+s-1]=count;//下面三个赋值语句是用④号模板覆盖 
    68         bord[tr+s-1][tc+s]=count;
    69         bord[tr+s][tc+s-1]=count;
    70         cover(tr+s,tc+s,s,dr,dc);
    71         
    72         cover(tr,tc,s,tr+s-1,tc+s-1);
    73         cover(tr,tc+s,s,tr+s-1,tc+s);
    74         cover(tr+s,tc,s,tr+s,tc+s-1);
    75     }
    76 }

    策略c:

    先不停地分割,当分割到不能再分割时依次填充四个size=2的子棋盘,然后回溯到size=4的棋盘填充伪残缺块。
    然后回溯到size=8,重复刚才的过程,依次处理另外三个size=4的子棋盘。

    关键代码如下:

    完整代码:

     1 #include <iostream>
     2 #include <iomanip>
     3 
     4 using namespace std;
     5 
     6 int num=1,arr[100][100];
     7 void Cover(int tr,int tc,int size,int dr,int dc)
     8 {
     9     if(size<2) return ;
    10     int s;
    11     s=size/2;
    12     if(dr<(tr+s)&&dc<(tc+s))
    13     {
    14         Cover(tr,tc,s,dr,dc);
    15         Cover(tr,tc+s,s,tr+s-1,tc+s);
    16         Cover(tr+s,tc,s,tr+s,tc+s-1);
    17         Cover(tr+s,tc+s,s,tr+s,tc+s);
    18         arr[tr+s-1][tc+s]=num;
    19         arr[tr+s][tc+s-1]=num;
    20         arr[tr+s][tc+s]=num;
    21         num++;
    22     }
    23     else if(dr<(tr+s)&&dc>=(tc+s))
    24     {
    25         Cover(tr,tc,s,tr+s-1,tc+s-1);
    26         Cover(tr,tc+s,s,dr,dc);
    27         Cover(tr+s,tc,s,tr+s,tc+s-1);
    28         Cover(tr+s,tc+s,s,tr+s,tc+s);
    29         arr[tr+s-1][tc+s-1]=num;
    30         arr[tr+s][tc+s-1]=num;
    31         arr[tr+s][tc+s]=num;
    32         num++;
    33     }
    34     else if(dr>=(tr+s)&&dc<(tc+s))
    35     {
    36         Cover(tr,tc,s,tr+s-1,tc+s-1);
    37         Cover(tr,tc+s,s,tr+s-1,tc+s);
    38         Cover(tr+s,tc,s,dr,dc);
    39         Cover(tr+s,tc+s,s,tr+s,tc+s);
    40         arr[tr+s-1][tc+s-1]=num;
    41         arr[tr+s-1][tc+s]=num;
    42         arr[tr+s][tc+s]=num;
    43         num++;
    44     }
    45     else
    46     {
    47         Cover(tr,tc,s,tr+s-1,tc+s-1);
    48         Cover(tr,tc+s,s,tr+s-1,tc+s);
    49         Cover(tr+s,tc,s,tr+s,tc+s-1);
    50         Cover(tr+s,tc+s,s,dr,dc);
    51         arr[tr+s-1][tc+s-1]=num;
    52         arr[tr+s-1][tc+s]=num;
    53         arr[tr+s][tc+s-1]=num;
    54         num++;
    55     }
    56 }
    57 
    58 int main()
    59 {
    60     int k,x,y;
    61     int temp=1;
    62     cin>>k>>x>>y;
    63     arr[x][y]=0;
    64     for(int i=0;i<k;i++)
    65         temp=temp*2;
    66     Cover(0,0,temp,x,y);
    67     for(int a=0;a<temp;a++)
    68     {
    69         for(int b=0;b<temp;b++)
    70         {
    71             cout<<setw(3)<<arr[a][b];
    72         }
    73         cout<<endl;
    74     }
    75     return 0;
    76 }

    本问题可以参考:http://www.cnblogs.com/kahreman/archive/2011/08/08/2130613.html

  • 相关阅读:
    hdu2089 数位dp
    AIM Tech Round 3 (Div. 2)
    Codeforces Round #372 (Div. 2)
    src 小心得
    水平文字垂直居中
    点击验证码刷新(tp3.1)--超简单
    TP3.1 中URL和APP区别
    getField方法
    PHP截取中文无乱码函数——cutstr
    substr — 详解
  • 原文地址:https://www.cnblogs.com/huashanqingzhu/p/6890784.html
Copyright © 2020-2023  润新知