Description
对于一个数列a1,a2......am,其中a1 = 1,am = n , a1 < a2 < ... < am-1 < am 对于每个k(2<=k<=m),ak=ai+aj (1 <= i, j <= k-1),现给定n的值,要求m的最小值.
Input
整个测试有多组数据,每行一个数字N,N<=100,测试以数字零代表结束。
Output
输出有多行,每行一个数字,代表你的结果
Sample Input
5
7
12
15
77
0
Sample Output
4
5
5
6
9
HINT
Source
迭代搜索,用深度优先的话需要找出所有加法链,然后再取最小的,至少是n!的复杂度,用广度的话
找到的第一个加法链就是最短的,但是对空间占用太大
逐步深化的迭代搜索可以保证第一个找到的加法链就是最短的,又不需要太大的空间开销。
基本思想是控制回溯的搜索深度deep, 每次使deep加1,直到找到一条加法链
(更多优化):1.deep有一个下界,从此下界开始搜索,可以最大加快搜索进程
2.更多剪枝
3.最短加法链的上界,是一个幂树。
<pre name="code" class="cpp">#include<stdio.h>
#include<math.h>
#include<string.h>
#include<algorithm>
#include<map>
#include<iostream>
using namespace std;
int max1(int a, int b) {
return a > b ? a : b;
}
int gcd(int a, int b) {
return b ? gcd(b, a % b) : a;
}
int lcm(int a, int b) {
return a / gcd(a, b) * b;
}
int flag,deep;
int n;
int a[110];
void f(int ans, int step) {
if (ans == n) {
flag=0;
return;
}
if(step==deep)return;
a[step]=ans;
for(int i=step;i>=1;i--)
{
if(a[i]*2<a[step])return;//剪枝:如果a[i]的2倍都比a[step]小,那么之后的所有结果都只会更小,所以剪掉
for(int j=i;j>=1;j--)
{
if(a[i]+a[j]<=a[step])break;
if(a[i]+a[j]>n)continue;
f(a[i]+a[j],step+1);
}
}
return;
}
// 1 2 4 8 16 32 64
int main() {
// freopen("in.txt", "r", stdin);
// freopen("out.txt", "w", stdout);
while (scanf("%d", &n) != EOF && n) {
flag=1;
deep=0;
while(flag)
{
deep++;
f(1,1);
}
printf("%d\n", deep);
}
return 0;
}
/**************************************************************
Problem: 1252
User: xrq
Language: C++
Result: Accepted
Time:376 ms
Memory:1532 kb
****************************************************************/