Addition Chains

Posted ppxppx

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了Addition Chains相关的知识,希望对你有一定的参考价值。

POJ n<=100

洛咕 n<=10000

题意:满足如下条件的序列a被称为"加成序列":

\(1.a_1=1\)

\(2.a_m=n\)

\(3.a_1<a_2<...<a_m-1<a_m\)

\(4.\)对于每一个\(k(1≤k≤m)\)都存在有两个整数 \(i\)\(j(1≤i,j≤k-1,i\)\(j\) 可以相等 ) ,使得 \(a_k=a_i+a_j\)

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

分析:显然,\(a[1]=1,a[2]=2\),这两个可以直接特判,然后我们从序列的第3位开始搜起.设当前搜索到了位置k,我们直接枚举i和j,然后\(a[k]=a[i]+a[j]\).暴力的搜索框架就是这样.下面考虑优化.

序列的长度可以直接看做搜索深度,所以我们可以迭代加深,搜索深度从3开始每次加1,直到搜到一个合法的序列为止.

然后还有一些必要的剪枝:

剪枝一:枚举i和j时从大到小枚举,以便于更快地逼近n,减少状态数.

剪枝二:因为我们是从大到小枚举,所以如果当前的\(a[i]+a[i]\)或者\(a[i]+a[j]\)小于\(a[now-1]\)(保证序列单调递增),就可以直接break掉了.因为后面的只会更小.

剪枝三:对于不同的i和j,\(a[i]+a[j]\)可能相等,如果当前填入\(a[i]+a[j]\)搜索失败了,我们就标记一下,下次就不再填入这个数了.

剪枝四:因为\(a[now]\)最多是\(a[now-1]\)的两倍,所以如果我们发现每次都填最大仍会导致第dep位比n小,那么直接return 掉.

#include<iostream>
#include<cstdio>
#include<algorithm>
#include<cstring>
#include<cmath>
#include<queue>
#include<map>
#include<set>
#define ll long long
using namespace std;
inline int read()
    int x=0,o=1;char ch=getchar();
    while(ch!='-'&&(ch<'0'||ch>'9'))ch=getchar();
    if(ch=='-')o=-1,ch=getchar();
    while(ch>='0'&&ch<='9')x=x*10+ch-'0',ch=getchar();
    return x*o;

int n,dep,a[10005];
inline bool dfs(int now)
    if(now>dep)
        if(a[dep]==n)return true;
        return false;
    
    if(a[now-1]*(1<<(dep-now+1))<n)return false;//剪枝4
    map<int,int>fail;//剪枝3
    for(int i=now-1;i>=1;--i)//剪枝1的倒序枚举
        if(a[i]+a[i]<=a[now-1])break;//剪枝2
        for(int j=i;j>=1;--j)//避免重复,从第i位开始
            if(a[i]+a[j]<=a[now-1])break;//剪枝2
            if(a[i]+a[j]<=n&&!fail[a[i]+a[j]])
                a[now]=a[i]+a[j];
                if(dfs(now+1))return true;
                fail[a[i]+a[j]]=1;//剪枝3的标记操作
                a[now]=0;
            
        
    
    return false;

int main()
    while(1)
        n=read();if(!n)break;
        if(n==1)puts("1");continue;
        if(n==2)printf("1 2\n");continue;
        a[1]=1;a[2]=2;dep=3;
        while(1)//迭代加深,从3开始
            if(dfs(3))break;
            ++dep;
        
        for(int i=1;i<dep;++i)printf("%d ",a[i]);
        printf("%d\n",a[dep]);
    
    return 0;

以上是关于Addition Chains的主要内容,如果未能解决你的问题,请参考以下文章

LeetCode Range Addition II

BigQuery - 您可以通过 ALLOW_FIELD_ADDITION 添加值吗?

Leetcode: Range Addition

370. Range Addition

Range Addition

370 Range Addition