【迭代加深搜索】Addition Chains

【迭代加深搜索】Addition Chains

An addition chain for n is an integer sequence < a0, a1, a2, … , am > with the following four properties:
• a0 = 1
• am = n
• a0 < a1 < a2 < · · · < am−1 < am
• For each k (1 ≤ k ≤ m) there exist two (not neccessarily different) integers i and j (0 ≤ i, j ≤ k−1)
with ak = ai + aj
You are given an integer n. Your job is to construct an addition chain for n with minimal length.
If there is more than one such sequence, any one is acceptable.
For example, < 1, 2, 3, 5 > and < 1, 2, 4, 5 > are both valid solutions when you are asked for an
addition chain for 5.

Input

The input file will contain one or more test cases. Each test case consists of one line containing one
integer n (1 ≤ n ≤ 10000). Input is terminated by a value of zero (0) for n.

Output

For each test case, print one line containing the required integer sequence. Separate the numbers by
one blank.

Sample Input

5
7
12
15
77
0

Sample Output

1 2 4 5
1 2 4 6 7
1 2 4 8 12
1 2 4 5 10 15
1 2 4 8 9 17 34 68 77

【解析】

一、题目翻译
一个关于整数N的加法链是一个整数序列<A0, A1, …, Am>,满足如下的4个条件:

(1) A0 = 1

(2) Am = N

(3) A0 < A1 < … < Am-1 < Am

(4) 对于每一个k(1 <= k <= m),存在两个整数i和j(0 <= i, j <= m-1且i和j可以相等),使得Ak = Ai + Aj

你的任务是对于给定的N,找出长度最短的加法链,也就是整数序列的个数尽可能少。如果有多个长度相同的方案,输出任意一个方案。

例如,对于N = 5, <1,2,3,5> 和 <1,2,4,5> 都是可行解。

二、解决方法
这道题容易想到用搜索来做,其实也没什么好讲的。我想这道题不同于其他题的特点也就是需要我们去控制搜索时的深度,而这道题的解决方案具体在代码中。

AC代码:

#include<cstdio>
#include<cstring>
#include<cmath>
#include<iostream>
using namespace std;
#define MAXN 10005
int n,dep;
int a[MAXN],p[MAXN];
bool f=0;
void Init()//初始化,以后会用到
{
    int cnt=1;
    p[0]=cnt;
    for(int i=1;i<=20;i++)
    p[i]=(cnt*=2);
}
void print()//输出
{
    for(int i=1;i<dep;i++)
        printf("%d ",a[i]);
    printf("%d\n",a[dep]);
}
void dfs(int i)//搜索
{
    if(f) return ;//如果出解便不需要再继续搜索
    if(i==dep)//到达最大的深度
    {
        if(a[dep]==n)//满足最后一个等于n的第一组数据便是解
        {
            f=1;//标记
            print();//输出
        }
        return ;
    }
    else//如果未到达最高点
    {
        for(int k=i;k>=1;k--)//枚举另外一个数(题目要求对于每一个k(1 <= k <= m),存在两个整数i和j(0 <= i, j <= m-1且i和j可以相等),使得Ak = Ai + Aj),当然我们的愿望是尽量的大。
        {
            a[i+1]=a[i]+a[k];
            if(a[i+1]<=n)//满足
            {
                if(a[i+1]*p[dep-i-1]<n) return ;//如果剩下的数我们都选它还不能到达n,愿望破灭。
                dfs(i+1);
                if(f) return ;
            }
        }
    }
}
int main()
{
    a[1]=1;
    a[2]=2;
    Init();
    while(scanf("%d",&n)&&n)
    {
        f=0;
        if(n==1) {printf("1\n");continue; }//特判
        for(dep=floor(log2(n))-1;dep<=n;dep++)//控制范围,加快速度
            if(!f) dfs(2);
            else break;
    }
}

猜你喜欢

转载自blog.csdn.net/qq_37862149/article/details/79851124