ZOJ1937 Addition Chains

题目描述

原题来自:ZOJ 1937

已知一个数列 a0,a1...ama_0,a_1...a_ma0,a1...am(其中 a0=1,am=n,a0<a1<a2<...<am−1<ama_0 = 1 , a_m = n , a_0 lt a_1 lt a_2 lt ... lt a_{m-1} lt a_ma0=1,am=n,a0<a1<a2<...<am1<am)。对于每个 kkk,需要满足 ak=ai+aja_k=a_i+a_jak=ai+aj0≤i,j≤k−10 leq i , j leq k-10i,jk1,这里 iii 与 jjj 可以相等)。

现给定 nnn 的值,要求 mmm 的最小值(并不要求输出),及这个数列每一项的值(可能存在多个数列,只输出任一个满足条件的就可以了)。

输入格式

多组数据,每行给定一个正整数 nnn 。

输入以 000 结束。

输出格式

对于每组数据,输出满足条件的长度最小的数列。

样例

样例输入

5
7
12
15
77
0

样例输出

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

很好玩的题,其实不用推什么公式,虽然数据范围是100
但是把搜索写好了,再加一点剪枝就可以
如果说有什么问题就是我们学校的数据锅了
下面给出代码:
#include<iostream>
#include<cmath>
#include<cstdio>
#include<cstdlib>
#include<cstring>
#include<string>
#include<algorithm>
#include<queue>
using namespace std;
inline int rd(){
    int x=0,f=1;
    char c=getchar();
    for(;!isdigit(c);c=getchar()) if(c=='-') f=-1;
    for(;isdigit(c);c=getchar()) x=x*10+c-'0';
    return x*f;
}
inline void write(int x){
     if(x<0) putchar('-'),x=-x;
     if(x>9) write(x/10);
     putchar(x%10+'0');
}
int a[100000];
int book[100000];
int ans,n;
bool dfs(int step){
    memset(book,0,sizeof(book));
    if(step>ans){//剪枝,在长度超过我们所需的时候,判断是否已经完成 
        if(a[ans]==n) return 1;
        return 0;
    }
    for(int i=step-1;i>=1;i--){
        for(int j=i;j>=1;j--){//从i开始,因为可以重复 
            if(a[i]+a[j]>n) continue;//取的值必须严格小于n 
            if(!book[a[i]+a[j]]){//不能取重复的值,严格递增 
                if(a[i]+a[j]<=a[step-1]) return 0;
                book[a[i]+a[j]]=1;
                a[step]=a[i]+a[j];
                int hh=a[step];
                for(int k=step+1;k<=ans;k++) hh*=2;//如果取这个值在所限定的个数内取最大值也到不了,就不能取 
                if(hh<n) break;
                if(dfs(step+1)) return 1;//递增长度,回溯 
                a[step]=0;
                book[a[i]+a[j]]=0;
            }
        }
    }
    return 0;
}
int main(){
    while(1){
        memset(a,0,sizeof(a));
        n=rd();
        if(n==0) return 0;//因为长度小,所以要特判 
        else if(n==1){
            printf("1
");
            continue;
        }
        else if(n==2){
            printf("1 2
"); 
            continue;
        }
        a[1]=1;
        a[2]=2;
        for(ans=3;!dfs(3);ans++);//判断每个长度是否可行,否则加一 
        for(int i=1;i<ans;i++) printf("%d",a[i]);
        printf("%d
",a[ans]);
    }
    return 0;
}
 
 
蒟蒻总是更懂你✿✿ヽ(°▽°)ノ✿
原文地址:https://www.cnblogs.com/WWHHTT/p/9754047.html