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