信息学奥赛一本通 1325:【例7.4】 循环比赛日程表

【题目链接】

ybt 1325:【例7.4】 循环比赛日程表

【题目考点】

1. 递归/递推:分形图
2. 分治

【解题思路】

考察输出样例,可以发现规律,当矩阵边长为1,2,4,8的时候,如果将矩阵分为四个区域,那么左上方与右下方相同,右上方与左下方相同。
在这里插入图片描述
根据这一规律,该题有递推与递归两种解法。

解法1:递推

一个边长为n的矩阵,边长的一半记为half, h a l f = n 2 half = \frac{n}{2} half=2n。将该矩阵等分为四部分:

  • 左上部:行坐标:1~half,列坐标:1~half
  • 右上部:行坐标:1~half,列坐标:half+1~n
  • 左下部:行坐标:half+1~n,列坐标:1~half
  • 右下部:行坐标:half+1~n,列坐标:half+1~n

左上部的数据是已知的,当前需要做的是根据左上部的数据推导出其他三个部分的数据。
记左上部第i行第j列的位置为(i,j),值记为a[i][j],其对应的其他三部分的位置及值的情况如下

  • 左上部(i, j)对应右上部(i,j+half),数值应该为在a[i][j]基础上增加half,即a[i][j+half] = a[i][j] + half
  • 左上部(i, j)对应左下部(i+half,j),数值应该为在a[i][j]基础上增加half,即a[i+half][j] = a[i][j] + half
  • 左上部(i, j)对应右下部(i+half,j+half),数值与a[i][j]相同,即a[i+half][j+half] = a[i][j]

先将a[1][1]设为1,然后考虑边长为2的矩阵,此时左上部为a[1][1]是已知的。填充好边长为2的矩阵后,考虑边长为4的矩阵,此时左上部为已知的。而后再考虑边长为8的矩阵。每次考虑的矩阵边长乘以2,最后考虑边长为 2 m 2^m 2m的矩阵。

解法2:递归
  • 递归问题:用从s开始的数字填充左上角为(x,y),边长为k的矩阵。
  • 递归关系:
    half = k/2,表示矩阵边长的一半。将以(x,y)为左上角,边长为k的矩阵分为四个部分:
  • 左上部:以(x,y)为左上角,边长为half,数字从s开始
  • 右上部:以(x,y+half)为左上角,边长为half,数字从s+half开始
  • 左下部:以(x+half,y)为左上角,边长为half,数字从s+half开始
  • 右下部:以(x+half,y+half)为左上角,边长为half,数字从s开始
    填充这四个部分的矩阵是子问题,可以递归求解。四个子矩阵填充后,本矩阵即填充完毕。
  • 递归出口:如果该矩阵边长为1,左上角为(x,y),数字从s开始。那么就直接赋值a[x][y]=s

【题解代码】

解法1:递推
#include<bits/stdc++.h>
using namespace std;
#define N 1025
int a[N][N];
int main()
{
    int n, m, half;
    cin >> m;
    n = pow(2, m);//矩阵最大边长 
    a[1][1] = 1;
    for(int k = 2; k <= n; k *= 2)//填充边长为k的矩阵 
    {
        half = k/2;//矩阵边长的一半 
        for(int i = 1; i <= half; ++i)
            for(int j = 1; j <= half; ++j)
            {
                a[i+half][j+half] = a[i][j];//填充右下部 
                a[i][j+half] = a[i+half][j] = a[i][j] + half;//填充右上部与左下部 
            }
    } 
    for(int i = 1; i <= n; ++i)//输出矩阵 
    {
        for(int j = 1; j <= n; ++j)
            cout << a[i][j] << ' ';
        cout << endl;
    }
    return 0;
}
解法2:递归
#include<bits/stdc++.h>
using namespace std;
#define N 1025
int a[N][N];
//要填的数字为s~s+k-1, 矩阵边长:k, 矩阵左上角为(x, y) 
void setMatrix(int s, int k, int x, int y)
{
    if(k == 1)
    {
        a[x][y] = s;
        return;
    }
    int half = k/2;
    setMatrix(s, half, x, y);//左上部 
    setMatrix(s+half, half, x, y+half);//右上部 
    setMatrix(s+half, half, x+half, y);//左下部 
    setMatrix(s, half, x+half, y+half);//右下部
}
int main()
{
    int n, m;
    cin >> m;
    n = pow(2, m);//矩阵边长 
    setMatrix(1, n, 1, 1);//左上角为(1,1),填充数值为1~n 
    for(int i = 1; i <= n; ++i)//输出矩阵 
    {
        for(int j = 1; j <= n; ++j)
            cout << a[i][j] << ' ';
        cout << endl;
    }
    return 0;
}
  • 4
    点赞
  • 19
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值