题目背景
借助反作弊系统,一些在月赛有抄袭作弊行为的选手被抓出来了!
题目描述
现有 2^n*2^n (n≤10) 名作弊者站成一个正方形方阵等候 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("\n"); } return 0; }
仔细观察输出的数据,其实都是它上方的数字异或它上方右边的数字,其实就是不进位加法。
于是乎,开始复习一下,二进制的位运算吧!!!
位运算:
其实二进制的位运算不难掌握,共有5种:与,或,异或,左移,右移。
归纳一下:(二进制下用1表示真,0表示假)
与其实就是数学的且,两个都为真才是真。
或则和数学的一样,有真为真。
异或是,两者相同为0,不同为1