UVA529 Addition Chains


题意:

一个与 nn 有关的整数加成序列 $<a_0,a_1,a_2,...,a_m>$ 满足以下四个条件:
1.$a_0=1$

2.$a_m=n$
3.$a_0<a_1<a_2<...<a_{m-1}<a_m$
4. 对于每一个 k(1≤k≤m) 都存在有两个整数 i 和 j(0≤i,j≤k-1,i和 j 可以相等 ) ,使得 $a_k=a_i+a_j$​
你的任务是:给定一个整数 nn ,找出符合上述四个条件的长度最小的整数加成序列。

如果有多个满足要求的答案,只需要输出任意一个解即可。
举个例子,序列<1,2,3,5> 和 <1,2,4,5> 均为 n=5 时的解。

一看就是搜索,于是爆搜。。。

然而,这是个迭代加深搜索。。。

剪枝如下:


1.优化搜索顺序
显然倒序枚举更有可能得到可行解。

让数大一些,尽可能接近n;

2.排除不可行解
我们发现,对于加成数列的要求还有一个,即 $a_m=n$

假设当前已经通过枚举得出了 $a_i$ ,正准备搜索第 i+1 个数。

考虑通过当前形势下到第 m 项可以得到的最大值,显然,$max(a_{i+1})=a_i+a_i=2×a_i$​

$max(a_{i+2})=a_{i+1}+a_{i+1}=2×a_{i+1}=4×a_i=2^2×a_i$​

故由递推可得

$max(a_m)=2^{m-i}×a_i$​

所以在进行对 i+1 个数的搜索前,计算一下 $max(a_m)$ 是否可以达到 n ,

如果达不到则无需进行下一步的搜索。

#include<cstdio>
#include<iostream>
using namespace std;
#define love_nmr 0
int n;
bool flag;
int ans[10050];
int maxx;
inline void print()
{
    for(int i=1;i<maxx;i++)
        printf("%d ",ans[i]);
    printf("%d\n",ans[maxx]);
}
inline void dfs(int depth,int pos)
{
    if(depth==maxx+1)
    {
        if(ans[maxx]==n)
            flag=true;
        return;    
    }
    for(int i=depth-1;i>=pos;i--)
    {
        for(int j=i;j>=1;j--)
        {
           int f=ans[depth]=ans[i]+ans[j];
           for(int is=pos+1;is<=maxx;is++) f<<=1;
           if(f<n)break;
           dfs(depth+1,i+1);
           if(flag)return;
           ans[depth]=0;
        }
    }
}
int main()
{
    while(~scanf("%d",&n)&&n)
    {
        if(n==1)
        {
            printf("1\n");
            continue;
        }
        flag=false;
        ans[1]=1;
        for(int i=2;i<=n;i++)
        {
            maxx=i;
            dfs(2,1);
            if(flag)
            {
                print();
                break;
            }
        }
    }
}

猜你喜欢

转载自www.cnblogs.com/olinr/p/9429690.html