棋盘覆盖(一) ACM

时间:2023-03-09 15:10:50
棋盘覆盖(一) ACM

棋盘覆盖

描述

在一个2k×2k(1<=k<=100)的棋盘中恰有一方格被覆盖,如图1(k=2时),现用一缺角的2×2方格(图2为其中缺右下角的一个),去覆盖2k×2k未被覆盖过的方格,求需要类似图2方格总的个数s。如k=1时,s=1;k=2时,s=5

输入
第一行m表示有m组测试数据;
每一组测试数据的第一行有一个整数数k;
输出
输出所需个数s;
样例输入
3
1
2
3
样例输出
1
5
21

错误答案:   读完题后,首先就想到可以用 num = (2^k * 2^k - 1) / 3,轻松算出答案。于是就有了下面的程序,写完后才发现,这个题有坑!2^100次方这个数已经超过了整数变量的最大值,这个题应该用大数算法。

using namespace std;
int main()
{
int time, k;
cin >> time;
int nums[time];
int i = time;
while (i--) {
cin >> k;
nums[i] = (( << k) * ( << k) - ) / ;
}
i = time;
while(i--) {
cout << nums[i] << endl;
}
return ;
}

大数算法,简单说就是用数组来存储数值。而相应的进位等计算操作就需要手动编写。利用数组进行大数的加减乘等操作相对简单,但是除法就麻烦多了。num = (2^k * 2^k - 1) / 3利用这个公式来算大数,显然不太明智。所以我们需要找到更好算法,充分利用计算机的循环操作。

num = (^ * ^ - ) /  =  = ^ + ^ + ^ + ^
num = (^ * ^ - ) / = = ^ + ^ + ^
num = (^ * ^ - ) / = = ^ + ^
num = (^ * ^ - ) / = = ^

大家不用我说就能发现里面的规律了吧。利用这个公式就可以避免除以3的计算。

j = k - 1

num = 2^(2*j) + 2^(2*j-2) + …… + 2^0

num = (((2^2 + 1) * 2^2 + 1) * 2^2 + 1) * 2^2 + 1

可以进一步转换公式,变换成利于循环操作

然后结合数组存储大数的方法就可以得到下面的程序

#include<iostream>
#include<string.h>
using namespace std; int main()
{
int sum;
cin >> sum;
int total[sum][];
int n = sum;
while(n--)
{
int *a = total[n];
memset(a, , * sizeof(int));
int size;
cin >> size;
a[] = ;
int i, j, k;
for(i = ;i <= size; ++i)
{
for(j = ; j < ; ++j)
a[j] = * a[j];
a[]++;
for(j = ; j < ; ++j)
{
a[j+] += a[j] / ;
a[j] = a[j] % ;
}
}
}
// 输出
n = sum;
while(n--)
{
int i, j;
int *a = total[n];
for(i = ; i >= ; --i)
if(a[i])
break;
for(j = i; j >= ; --j)
cout << a[j];
cout << endl;
}
return ;
}

另一种思路:

如果这个题不是求L型方格的数量,而且让你绘制出摆放方格后的棋盘呢。这就变成了另外一个题,而相应的算法也完全不同。这里就需要运用分治算法。