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;
}