OJ技巧之打表(用空间换时间)

版权声明:本文为博主原创文章,遵循 CC 4.0 BY-SA 版权协议,转载请附上原文出处链接和本声明。
本文链接: https://blog.csdn.net/Africa_South/article/details/101780616

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;
}

简直毒瘤。

猜你喜欢

转载自blog.csdn.net/Africa_South/article/details/101780616