Addition Chains

题目描述:

一个与 n 有关的整数加成序列 < a0 , a1 , a2 ...am> 满足一下四个条件:

1.a0=1

2.am=n

3.a0<a1<a2<...<am

4.对于每个( 1≤k≤m )都存在有两个整数 i 和 j (0 ≤ i , j  ≤ k - 1 , i 和 j可以相等),使得ak=ai+aj

你的任务是:给定一个整数 n ,找出符合上述四个条件的长度最小的整数加成序列。如果有多个满足要求的答案,只需要输出任意一个解即可。

举个例子:序列< 1,2,3,5 >和< 1,2,4,5 >均为 n = 5 时的解

 

输入格式:

多组数据,每行给定一个正整数n。输入以0结束。

输出格式:

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

 

样例输入:

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

思路:

  看了书之后才知道这题是用搜索。(蒟蒻的我只会暴力枚举

  那么怎么搜索又成为了一个问题——其实可以依次搜索一位k, 枚举之前的i, j, 把a[i] + a[j] 加到a[k]的位置上, 然后接着搜索;

  这样还是AC不了。

  这时就需要考虑剪枝。

  对于剪枝:

  ①尽量从达到小枚举i,j让序列的数尽快逼近n;(贪心思想)

  ②为了不重复搜索,用一个bool数组存a[i] + a[j] 是否已经被搜过;

AC代码:

#include<cstdio>
#include<cstring>
#include<cmath>
#include<algorithm>
#include<cstdlib>
#include<iostream>
#include<stack>
#include<queue>
#include<deque>
#include<vector>
#include<map>
#include<set>
using namespace std;
#define maxn 1100
int n,ans,a[maxn];
bool use[maxn];
inline int read()
{
    char kr=0;
    char ls;
    for(;ls>'9'||ls<'0';kr=ls,ls=getchar());
    int xs=0;
    for(;ls>='0'&&ls<='9';ls=getchar())
    {
        xs=xs*10+ls-48;
    }
    if(kr=='-') xs=0-xs;
    return xs;
}
inline bool dfs(int stp)
{
    memset(use,0,sizeof(use));
    if(stp>ans)
    {
        if(a[ans]==n) return true;
        else return false;
    }
    for(register int i=stp-1;i>=1;i--)
    {
        for(register int j=i;j>=1;j--)
        {
            if(a[i]+a[j]>n) continue;
            if(!use[a[i]+a[j]])
            {
                if(a[i]+a[j]<=a[stp-1]) return false;
                use[a[i]+a[j]]=true;
                a[stp]=a[i]+a[j];
                if(dfs(stp+1)) return true;
                a[stp]=0;
                use[a[i]+a[j]]=false;
            }
        }
    }
}
int main()
{
    while(n=read(),n!=EOF)
    {
        if(n==0) return 0;
        if(n==1)
        {
            printf("1\n");
            continue;
        }
        if(n==2)
        {
            printf("1 2\n");
            continue;
        }//特判一下上述三种情况 
        a[1]=1;a[2]=2;
        for(ans=3;!dfs(3);ans++);//搜索记录 
        for(register int i=1;i<=ans;i++)
        {
            printf("%d ",a[i]);
        }
        printf("\n");
        memset(a,0,sizeof(a));
    }
return 0;
}

洛谷谜一般的评测TLE,在POJ上提交AC了。

posted @ 2018-09-14 19:35  落笔映惆怅丶  阅读(541)  评论(0编辑  收藏  举报