棋盘覆盖
- 描述
-
在一个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; 样例输入
-
3123
样例输出 -
1521
-
错误答案: 读完题后,首先就想到可以用 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] = ((1 << k) * (1 << k) - 1) / 3; } i = time; while(i--) { cout << nums[i] << endl; } return 0;}
大数算法,简单说就是用数组来存储数值。而相应的进位等计算操作就需要手动编写。利用数组进行大数的加减乘等操作相对简单,但是除法就麻烦多了。num = (2^k * 2^k - 1) / 3利用这个公式来算大数,显然不太明智。所以我们需要找到更好算法,充分利用计算机的循环操作。
num = (2^4 * 2^4 - 1) / 3 = 85 = 2^6 + 2^4 + 2^2 + 2^0num = (2^3 * 2^3 - 1) / 3 = 21 = 2^4 + 2^2 + 2^0num = (2^2 * 2^2 - 1) / 3 = 5 = 2^2 + 2^0num = (2^1 * 2^1 - 1) / 3 = 1 = 2^0
大家不用我说就能发现里面的规律了吧。利用这个公式就可以避免除以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
#include using namespace std;int main(){ int sum; cin >> sum; int total[sum][100]; int n = sum; while(n--) { int *a = total[n]; memset(a, 0, 100 * sizeof(int)); int size; cin >> size; a[0] = 1; int i, j, k; for(i = 2;i <= size; ++i) { for(j = 0; j < 100; ++j) a[j] = 4 * a[j]; a[0]++; for(j = 0; j < 99; ++j) { a[j+1] += a[j] / 10; a[j] = a[j] % 10; } } } // 输出 n = sum; while(n--) { int i, j; int *a = total[n]; for(i = 99; i >= 0; --i) if(a[i]) break; for(j = i; j >= 0; --j) cout << a[j]; cout << endl; } return 0;} 另一种思路:
如果这个题不是求L型方格的数量,而且让你绘制出摆放方格后的棋盘呢。这就变成了另外一个题,而相应的算法也完全不同。这里就需要运用分治算法。