第1部分 基础算法(提高篇)--第3章 深搜的剪枝技巧1443:【例题4】Addition Chains

1443:【例题4】Addition Chains

时间限制: 1000 ms 内存限制: 65536 KB
提交数: 968 通过数: 478
【题目描述】
已知一个数列a0,a1……am,其中a0=1,am=n; a0<a1<a2<……<am−1<am。对于每个k(1≤k≤m)满足ak=ai+aj(0≤i,j≤k−1),这里i与j可以相等。

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

【输入】
多组数据,每行给定一个正整数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


思路:

#include<iostream>
#include<cstdio>
#include<algorithm>
#include<cmath>
#include<cstring>
#define INF 0X3F3F3F3F
#define N 2019
using namespace std;

int n,minn,ans[N],a[N];
//n是序列的最大值
//minn是拆数字最小层数 
//ans存答案
//a是一个过程中起记录作用的数组 

void dfs(int x)  //递归第x层 
{
    if(x-1 > minn) return ;  //超过最小层数,剪枝 
    if(a[x-1] > n) return;   //上一层的数字大于最大值n,剪枝 
    if(a[x-1] == n)  //上一层的数字=n,有希望构成一个完整解答 
    {
        if((x-1) >= minn) return; //层数超了 
           minn = x-1;   //记下暂定答案 
        for(int i=1;i < x;i++) ans[i] = a[i];
    }
    else
    {
        for(int j = x-1;j >= 1;j--)  
        //ak=ai+aj,倒着枚举,看看能否继续扩展下一层 
        {
            if(a[x-1]+a[j] <= n)
            {
                a[x] = a[x-1]+a[j];  //可以继续扩展 
                dfs(x+1); 
                a[x] = 0;  //回溯 
            }
        }
    }
}

int main()
{
    while(scanf("%d",&n) != EOF) //输入非空 
    {
        if(n == 0) break;
        else
        {
            a[1] = 1;  //初始化第一层为1 
            minn = INF;  //拆数字的最小层数 
            dfs(2);  //从第二层开始递归 
            for(int i = 1;i <= minn;i++) printf("%d ",ans[i]); //确定层数,输出答案 
            printf("\n");
        }
    }
    return 0;
}
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章