经过一夜难以入眠的煎熬,我戴着熊猫眼滚下床,打开电脑,想着昨天那道做不出的题目,心里有所不甘。于是,有了今天。
今天,我一打开电脑,进入oj系统,看着题目,信心满满。于是,有了以下的总结:
①这是一支开启我训练之门的钥匙:
=================================================================================================================
题目描述如下:
有N个士兵站成一队列, 现在需要选择几个士兵派去侦察。为了选择合适的士兵, 多次进行如下操作: 如果队列超过三个士兵, 那么去除掉所有站立位置为奇数的士兵, 或者是去除掉所有站立位置为偶数的士兵。直到不超过三个战士,他们将被送去侦察。现要求统计按这样的方法,总共可能有多少种不同的正好三个士兵去侦察的士兵组合方案。
注: 按上法得到少于三士兵的情况不统计。1 <= N <= 2的32次方-1
输入格式
有多行,每行一个数字N,最后一行是0
输出格式
对每一行的数字N,输出针对N的方案数
直到没有数字
输入样例
10
4
0
输出样例
2
0
=================================================================================================================
思考过程:
这里是奇数分一半,偶数分一半,那么我们可以这样思考:
“等价转换”思想:实际上这种做法等同于分左右两半。
“递归“思想:你想一下,分成两半后,又是同样的问题(即继续分两半)--所谓的子问题,一直到不能或者不需要再分为止。
=================================================================================================================
细节上引发的问题:
以上思考形成的算法会带来一个问题:如果数据过大,那么该程序的运行时间是难以接受的。
解决方法:
”记忆搜索“思想:当数据很大的时候,你会容易发现”数据小的部分“已经重复计算了很多次了,所以这种思想就是"把重复计算很多次的结果给储存起来,等到以后
处理时遇到相同的问题,我们就可以直接拿结果来用,而不用再重复计算“。
其实”记忆搜索“这种思想在很多方面都有体现(特别是在递归上的应用):求高次幂运算(例如:2的100次方),fibnacci数列的非递归求法,给范围求素数个数etc。
=================================================================================================================
源代码:
#include <stdio.h>
//传说中的记忆搜索,能够解决一些超时问题(出现多次重复计算)
int record[10000];
int DealWith(int m, int n)
{
int tmp = n - m + 1;
if (tmp < 10000 && record[tmp] != -1)
return record[tmp];
else if ( tmp < 3)
return 0;
else if ( tmp == 3)
return 1;
else {
int ct = DealWith(m, m + tmp / 2 - 1) + DealWith(m + tmp / 2, n);
if ( tmp < 10000 )
record[tmp] = ct;
return ct;
}
}
int main()
{
for (int i = 0; i < 10000; ++i)
record[i] = -1;
int n;
while ( scanf( "%d", &n ) && n != 0 ) {
printf("%d\n", DealWith( 1, n ) );
}
return 0;
}
=================================================================================================================