版权声明:本文为博主原创文章,遵循 CC 4.0 BY-SA 版权协议,转载请附上原文出处链接和本声明。
1. 前言
有时候求解OJ算法题,会遇到多样例测试的情况,而且样例之间的求解过程有重复,则我们可以使用打表技巧,将求解过的样例结果(或者所有可能需要用到的结果)事先计算并存储下来,称之为打表
。
然后,每当求解一个样例时,即可直接取出结果,当样例数较多时,则可以节省大量不必要的重复。
2.例子
2.1 生成元
原题链接:UVa1583
题解
#include<stdio.h>
#include<string.h>
#include<stdlib.h>
#include<iostream>
using namespace std;
const int MAXN = 100010;
int book[MAXN];
int main() {
// 先进行打表,且生成元不为0
for (int i = 1; i < MAXN; i++) {
int sum = i, tmp = i;
while (tmp) {
sum += (tmp%10);
tmp /= 10;
}
if (i < book[sum] || book[sum] == 0) book[sum] = i;
}
int t, n;
scanf("%d", &t);
while (t--) {
scanf("%d", &n);
printf("%d\n", book[n]);
}
return 0;
}
2.2 火柴棒等式
当然,2.1是将打表的过程放在正式求解的过程中的,有时候,对于数据规模较小,但是算法复杂度又比较高的情况,可以事先在另一程序计算出某些数据的结果,然后复制到主程序中。说不定,一碰巧就AC了。
打表法具有快速,易行(可以写暴力枚举程序)
的特点,缺点是代码可能太大,或者情况覆盖不完
原题链接:P1149 火柴棒等式
打表分析:
本例中,n <= 24,则我们可以先用暴力解法求出解进行打表。
#include<stdio.h>
#include<string.h>
#include<stdlib.h>
#include<iostream>
using namespace std;
int val[10] = { 6,2,5,5,4,5,6,3,7,6 };
int need(int num) {
// 数字num需要的火柴数
int sum = 0;
while (num / 10) { // 防止num = 0
sum += val[num % 10];
num /= 10;
}
sum += val[num];
return sum;
}
int ans[25]; // n < 25 时的答案
int main() {
int a, b;
for (int a = 0; a <= 1111; a++) {
for (int b = 0; b <= 1111; b++) {
int sum = need(a) + need(b) + need(a + b) + 4;
if (sum <= 24) ans[sum]++;
}
}
for (int i = 0; i < 25; i++) {
printf("%d %d\n", i, ans[i]);
}
return 0;
}
输出:
0 0
1 0
2 0
3 0
4 0
5 0
6 0
7 0
8 0
9 0
10 0
11 0
12 0
13 1
14 2
15 8
16 9
17 6
18 9
19 29
20 39
21 38
22 65
23 88
24 128
则我们直接写出结果
#include<iostream>
using namespace std;
int ans[]={0,0,0,0,0,0,0,0,0,0,0,0,0,1,2,8,9,6,9,29,39,38,65,88,128};
int n;
int main(){
cin>>n;
cout<<ans[n]<<'\n';
return 0;
}
简直毒瘤。