170. 加成序列 - AcWing题库 满足如下条件的序列 (序列中元素被标号为 )被称为“加成序列”:
- 对于每个 ()都存在两个整数 i 和 j (, 和 可相等),使得 。
你的任务是:给定一个整数 ,找出符合上述条件的长度 最小的“加成序列”。
如果有多个满足要求的答案,只需要找出任意一个可行解。
输入格式
输入包含多组测试用例。
每组测试用例占据一行,包含一个整数 。
当输入为单行的 时,表示输入结束。
输出格式
对于每个测试用例,输出一个满足需求的整数序列,数字之间用空格隔开。
每个输出占一行。
数据范围
输入样例:
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
思路
没思路就考虑爆搜, 搜索顺序: u 为当前是第几项, path数组记录当前的数列 1 2 3 … 枚举当前项的值是什么, 从之前几个数相加得出
优化剪枝:
- 值越大的分支越少, 从大到小枚举之前的组合
- 1+3 和 3+1 得出的值相同, 故以组合方式枚举
- 同样的 2+3 和 1+4 的值也相同, 在搜索时声明st布尔数组判断某数是否被没举过
- 简单给一个数128, 显然1 2 4 8 16 32 64 128是最短的序列, 其搜索深度为8, 这给了一个启示, 题目n<100, 也就是说正解的层数不深, 但我们如果枚举所有情况的话会搜的非常深, 故可以使用迭代加深优化。
代码
const int N = 110;
int path[N];
int n;
bool dfs(int u, int depth)
{
if(u > depth) return false; // 搜到最后还没搜到就是失败了
if(path[u - 1] == n) return true;
bool st[N] = {0};
for(int i = u - 1; i >= 0; i--)
for(int j = i; j >= 0; j--)
{
int t = path[i] + path[j];
if(t > n || st[t] || t <= path[u - 1]) continue;
st[t] = true;
path[u] = t;
if(dfs(u + 1, depth)) return true;
}
return false;
}
int main()
{
path[0] = 1;
while(cin >> n, n)
{
int depth = 1;
while(!dfs(1,depth))
depth++;
for(int i = 0; i < depth; i++)
cout << path[i] << " ";
cout << endl;
}
return 0;
}