zoukankan      html  css  js  c++  java
  • 洛谷 P5461 赦兔战俘

    题目背景

    借助反作弊系统,一些在月赛有抄袭作弊行为的选手被抓出来了!

    题目描述

    现有 2^n*2^n (n10) 名作弊者站成一个正方形方阵等候 kkksc03 的发落。kkksc03 决定赦免一些作弊者。他将正方形矩阵均分为 4 个更小的正方形矩阵,每个更小的矩阵的边长是原矩阵的一半。其中左上角那一个矩阵的所有作弊者都将得到赦免,剩下 3 个小矩阵中,每一个矩阵继续分为 4 个更小的矩阵,然后通过同样的方式赦免作弊者……直到矩阵无法再分下去为止。所有没有被赦免的作弊者都将被处以棕名处罚。

    给出 nn,请输出每名作弊者的命运,其中 0 代表被赦免,1 代表不被赦免。

    输入格式

    一个整数 n

    输出格式

    2^n *2^n的 01 矩阵,代表每个人是否被赦免。数字之间有一个空格。

    输入输出样例

    输入 #1
    3
    输出 #1
    0 0 0 0 0 0 0 1
    0 0 0 0 0 0 1 1
    0 0 0 0 0 1 0 1
    0 0 0 0 1 1 1 1
    0 0 0 1 0 0 0 1
    0 0 1 1 0 0 1 1
    0 1 0 1 0 1 0 1
    1 1 1 1 1 1 1 1

    自己的想法是用递归来写,代码是这样的:
    #include<iostream>
    #include<stdio.h>
    #include<algorithm>
    #include<string.h>
    #include<math.h>
    using namespace std;
    int n,p=1,a[1050][1050];
    void di(int l,int x,int y )
    {
        if(l == 2)
        {
            a[x][y] = 0;
            return ;
        }
        for(int i = x ; i <= x + l/2 - 1 ; i++)
        {
            for(int j = y ; j <= y + l/2 -1 ; j ++)
            {
                a[i][j] = 0;
            }
        }
        
        di(l/2, x+l/2, y);
        di(l/2, l/2+x, l/2+y);
        di(l/2, x, y+l/2);
    }
    int main()
    {
        cin >> n;
        for(int i = 1 ; i <= n ; i ++)
        {
            p*=2;
        }
        
        for(int i = 1 ; i <= p ;i ++)
        {
            for(int j = 1 ; j <= p ; j++)
            {
                a[i][j] = 1;
            }
        }
        
        di(p,1,1);
        
        for(int i = 1 ; i <= p ; i ++) {
            for(int j = 1 ; j <= p ; j++)
            {
                cout << a[i][j];
            j == p ? cout << endl:cout << " "; 
            }
            cout << endl;
        }
    }

    因为是2的n次方的二维数组,输入n,要求出2^n 的值,并把a[2^n][2^n]全设为1,等递归的时候,对应情况设置为0;

    因为每次进行的步骤都是一样的,都是讲正方形的二维数组的长宽除2,然后将左上角的所有1变为0,因此想到了递归,直到边长为2了,只用把此正方形的最左上角设置为0,即可结束递归。

    但是看了看大佬的方法,还有更简便的,只用了位运算的方法!

    #include<algorithm>
    #include<iostream>
    #include<cstring>
    #include<cstdio>
    
    int n;
    int a[1234][1234];
    int main()
    {
        scanf("%d",&n);
        n = (1<<n);  //左移
        a[0][n+1] = 1;
        for(re int i=1;i<=n;++i)
        {
            for(re int j=1;j<=n;++j)
            {
                a[i][j] = a[i-1][j] ^ a[i-1][j+1];  //异或
                printf("%d ",a[i][j]);
            }
            printf("
    ");
        }
        return 0;
    }

    仔细观察输出的数据,其实都是它上方的数字异或它上方右边的数字,其实就是不进位加法。

    于是乎,开始复习一下,二进制的位运算吧!!!

    位运算:

    其实二进制的位运算不难掌握,共有5种:与,或,异或,左移,右移。

     归纳一下:(二进制下用1表示真,0表示假)

    与其实就是数学的且,两个都为真才是真。

    或则和数学的一样,有真为真。

    异或是,两者相同为0,不同为1

  • 相关阅读:
    位运算
    LeetCode(230):二叉树中的第K小元素
    LeetCode(69):二分法求平方根
    TCP如何保证传输可靠性
    2种方法(递归+BFS)求二叉树的最小/最大深度
    自动生成Mapper文件(基于Mybatis Maven插件)
    Git的使用
    Java关键字及其作用详解
    Vagrant安装Centos/7
    java servlet 几种页面跳转的方法及传值
  • 原文地址:https://www.cnblogs.com/wtzmz/p/12982398.html
Copyright © 2011-2022 走看看