用L-型砖块铺砌正方形棋盘

在正文之前,我能不能先吐槽一下,上周算法老师布置了实验,其中有些题目只有一句话。如果这个题目比较特殊,一句话就知道是什么题义,那咱们也就不说什么了。你看哈,任务二:实现铺砖问题的算法。只有这样一句话,就没了,没有题义,所以要了解具体的题目要求,具体的输入输出,是不是就要问一下度娘,搜完之后,分为两种,一种是一维的铺砖问题,一种是二维的铺砖问题。我就想着我们这样的水平老师可能想让我们写一维的那个题。然后我就屁颠屁颠的写完然后提交了。

等到第二天老师上课的时候,老师就把这个铺砖问题说是怎样的,要怎样写。然后我就呆了,心里有一万句骂人的话,但是咱不敢说啊,/(ㄒoㄒ)/~~

说正事,铺砖问题:
在 2^n * 2^n 棋盘上任意除去一个方格,剩下的棋盘能够被L-型完全覆盖。这是一个定理,是已证明的。
我从网上下载了证明过程的PDF,给你们分享一下。
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
现在我们要做的是,输入棋盘的边长,(注意:边长是2^n)

输出是 2^n* 2^n这样一个二维数组,同一块L-型砖用相同的数字来填充,不能填充的那一块,我们假定用-1来填充

来看一个输入输出样例:在这里插入图片描述
利用这个输入输出样例,我们来好好分析一下这道题,这是初始化的一个正方形棋盘:
在这里插入图片描述
接下来,我们任意选取一个方格,用-1来填充这个方格,表示这个方格是不用覆盖的那一个。
在这里插入图片描述
递归划分的第一次过程:
找到在哪一部分之后,对大部分平均分成四小部分。
然后把大部分中间的那四块,除了已经找到的那一部分,
剩下的三部分都填充上值v,v是递归传递的参数。
然后每次以此类推。
在这里插入图片描述
下面这个棋盘是第一次铺砖的结果,三个数字1表示,第一次铺覆盖的方格。
在这里插入图片描述
下面这个棋盘其实已经铺好了,用2填充的方格,表示第二次覆盖的方格。很明显 用2覆盖的方格它们也都是L-型的,是可以用L-型砖来覆盖的。
在这里插入图片描述
然后,我们再来看一下代码,因为我在写代码的过程中,二维数组不会传递参数/(ㄒoㄒ)/~~,所以写了一个类,里面有三个属性,然后用一维数组来完成这个题目。つ﹏⊂

#include<iostream>
using namespace std;
int N;    //所有的方块数量
int n1;   //全局变量边长

class A  //每一个方块是一个类
{
    public:
    int x;//方块的横坐标
    int y;//方块的纵坐标
    int key;//方块中填的值
};

void fun(A a[],int n,int x1,int y1,int x2,int y2,int v)
{
    //x1,y1递归部分的起始坐标
    //x2,y2递归部分的终止坐标
    int m=0; //判断不需要覆盖的那一块在哪一部分,左上m=1,右上m=2,左下m=3,右下m=4,
    for(int i=0;i<N;i++) //在递归的部分找到不需要铺的那一块在哪一部分,或者已经铺好的在哪一部分
    {
    if(a[i].x>=x1&&a[i].x<=x2&&a[i].y>=y1&&a[i].y<=y2)
    {
        if(a[i].key!=0)
        {
            if(a[i].x<n/2+x1)//在左边部分
            {
                if(a[i].y<n/2+y1)//左上
                    m=1;
                else//左下
                    m=3;
            }
            else//在右边部分
            {
                if(a[i].y<n/2+y1)//右上
                    m=2;
                else//右下
                    m=4;
            }
            break;
        }
    }
    }
//找到在哪一部分之后,对大部分平均分成四小部分。
//然后把大部分中间的那四块,除了已经找到的那一部分,
//剩下的三部分都填充上值v,v是递归传递的参数。
//对应上图的第3张棋盘图,然后每次以此类推。
    if(m==1) //不需要铺的那一块在第一部分的情况
    {
        for(int i=0;i<N;i++)
        {
            if(a[i].x==n/2+x1&&a[i].y==n/2-1+y1)
            {
                a[i].key=v;
            }
            if(a[i].x==n/2-1+x1&&a[i].y==n/2+y1)
            {
                a[i].key=v;
            }
            if(a[i].x==n/2+x1&&a[i].y==n/2+y1)
            {
                a[i].key=v;
            }
        }
    }
    if(m==2) //不需要铺的那一块在第二部分的情况
    {
        for(int i=0;i<N;i++)
        {
            if(a[i].x==n/2-1+x1&&a[i].y==n/2-1+y1)
            {
                a[i].key=v;
            }
            if(a[i].x==n/2-1+x1&&a[i].y==n/2+y1)
            {
                a[i].key=v;
            }
            if(a[i].x==n/2+x1&&a[i].y==n/2+y1)
            {
                a[i].key=v;
            }
        }
    }
    if(m==3) //不需要铺的那一块在第三部分的情况
    {
        for(int i=0;i<N;i++)
        {
            if(a[i].x==n/2-1+x1&&a[i].y==n/2-1+y1)
            {
                a[i].key=v;
            }
            if(a[i].x==n/2+x1&&a[i].y==n/2-1+y1)
            {
                a[i].key=v;
            }
            if(a[i].x==n/2+x1&&a[i].y==n/2+y1)
            {
                a[i].key=v;
            }
        }
    }
    if(m==4) //不需要铺的那一块在第四部分的情况
    {
        for(int i=0;i<N;i++)
        {
            if(a[i].x==n/2-1+x1&&a[i].y==n/2-1+y1)
            {
                a[i].key=v;
            }
            if(a[i].x==n/2+x1&&a[i].y==n/2-1+y1)
            {
                a[i].key=v;
            }
            if(a[i].x==n/2-1+x1&&a[i].y==n/2+y1)
            {
                a[i].key=v;
            }
        }
    }

    if(n!=2)//当n的规模不是2,就把当前规模分为四部分,进入下面的递归
    {
        v++;
        n=n/2;
        fun(a,n,x1,y1,x1+n-1,y1+n-1,v);//左上部分的递归
        fun(a,n,x1+n,y1,x1+n+n-1,y1+n-1,v);//右上部分的递归
        fun(a,n,x1,y1+n,x1+n-1,y1+n+n-1,v);//左下部分的递归
        fun(a,n,x1+n,y1+n,x1+n+n-1,y1+n+n-1,v);//右下部分的递归
    }
}
int main()
{
    int n;
    int v=1;    //方块第几次递归被铺上时的值
    cout<<"请输入方块的边长n(其中n=2^k):  ";
    cin>>n;
    n1=n;
    N=n*n;
    A a[n*n];
    int k=0;
    for(int i=0;i<n;i++)//棋盘的初始化,对应上面的第一张棋盘图
    {
        for(int j=0;j<n;j++)
        {
            a[k].x=i;
            a[k].y=j;
            a[k].key=0;
            k++;
        }
    }
    a[0].key=-1;   //可以任取一块置为-1,表示这一块不需要铺
    //这里选取的是第一块,对应上面的第二张棋盘图
    fun(a,n,a[0].x,a[0].y,a[N].x,a[N].y,v);
    for(int i=0;i<N;i++)//输出部分
    {
        cout<<a[i].key<<"\t";
        if((i+1)%n==0)
            cout<<endl;
    }
    return 0;
}

再来给你们看一下,其他输入的输出结果:
在这里插入图片描述
怎么说呢,我自己都没想到我可以写出来,可能是因为懒吧,拿到题目就想去网上搜一下,看别人怎么写的,可是这次我都没有找到,难为死我了/(ㄒoㄒ)/~~

你看我都可以写出来,所以你一定要相信,你也可以写出来的,说不定你会用更简单,更少的代码来解决,那你一定要给我留言哦。

L组件填图问题 1.问题描述 设B是一个n×n棋盘,n=2k,(k=1,2,3,…)。用分治法设计一个算法,使得:用若干个L条块可以覆盖住B的除一个特殊方格外的所有方格。其中,一个L条块可以覆盖3个方格。且任意两个L条块不能重叠覆盖棋盘。 例如:如果n=2,则存在4个方格,其中,除一个方格外,其余3个方格可被一L条块覆盖;当n=4时,则存在16个方格,其中,除一个方格外,其余15个方格被5个L条块覆盖。 2. 具体要求 输入一个正整数n,表示棋盘的大小是n*n的。输出一个被L条块覆盖的n*n棋盘。该棋盘一个方格外,其余各方格都被L条块覆盖住。为区别出各个方格是被哪个L条块所覆盖,每个L条块用不同的数字或颜色、标记表示。 3. 测试数据(仅作为参考) 输入:8 输出:A 2 3 3 7 7 8 8 2 2 1 3 7 6 6 8 4 1 1 5 9 9 6 10 4 4 5 5 0 9 10 10 12 12 13 0 0 17 18 18 12 11 13 13 17 17 16 18 14 11 11 15 19 16 16 20 14 14 15 15 19 19 20 20 4. 设计与实现的提示 对22k的棋盘可以划分成若干块,每块棋盘是原棋盘的子棋盘或者可以转化成原棋盘的子棋盘。 注意:特殊方格的位置是任意的。而且,L条块是可以旋转放置的。 为了区分出棋盘上的方格被不同的L条块所覆盖,每个L条块可以用不同的数字、颜色等来标记区分。 5. 扩展内容 可以采用可视化界面来表示各L条块,显示其覆盖棋盘的情况。 经典的递归问题, 这是我的大代码, 只是本人很懒, 不想再优化
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值