题目
一个与
n
n
n有关的整数加成序列
<
a
0
,
a
1
,
a
2
,
.
.
.
,
a
m
>
<a_0,a_1,a_2,...,a_m>
<a0,a1,a2,...,am>满足以下四个条件:
1.
a
0
=
1
1.a_0=1
1.a0=1
2.
a
m
=
n
2.a_m=n
2.am=n
3.
a
0
<
a
1
<
a
2
<
.
.
.
<
a
m
−
1
<
a
m
3.a_0<a_1<a_2<...<a_{m-1}<a_m
3.a0<a1<a2<...<am−1<am
4.
4.
4.对于每一个
k
(
1
≤
k
≤
m
)
k(1≤k≤m)
k(1≤k≤m)都存在有两个整数
i
i
i和
j
j
j
(
0
≤
i
,
j
≤
k
−
1
(0≤i,j≤k-1
(0≤i,j≤k−1,
i
i
i 和
j
j
j可以相等
)
)
),使得
a
k
=
a
i
+
a
j
a_k=a_i+a_j
ak=ai+aj
你的任务是:给定一个整数
n
n
n,找出符合上述四个条件的长度最小的整数加成序列。如果有多个满足要求的答案,只需要输出任意一个解即可。
举个例子,序列
<
1
,
2
,
3
,
5
>
<1,2,3,5>
<1,2,3,5>和
<
1
,
2
,
4
,
5
>
<1,2,4,5>
<1,2,4,5>均为
n
=
5
n=5
n=5时的解。
题解
蒟蒻的迭代加深入门题qwq- 首先我看到这道题的时候不知道该怎么写,
d
f
s
dfs
dfs?但是不知道序列中有几个数。
b
f
s
bfs
bfs?但是状态该怎么记录。
蒟蒻内心是崩溃的awsl 于是我就打了一个玄学暴搜,水过了30分qaq- 下面开始 b b bb bb正解
- 首先搜索一定要有明确的搜索框架,要明确自己要搜什么,不能漫无目的。对于这道题来说我们可以依次搜索序列中的每个位置 k k k,枚举 i , j i,j i,j,使得 x [ k ] = x [ i ] + x [ j ] x[k]=x[i]+x[j] x[k]=x[i]+x[j]。
- 但是这样搜无疑效率很低,我们考虑剪枝:
- 优化搜索顺序:为了让序列中的数字尽快接近 n n n,我们可以从大到小来枚举 i , j i,j i,j。
- 排除等效冗余:对于不同的 i , j i,j i,j, x [ i ] + x [ j ] x[i]+x[j] x[i]+x[j]可能是相等的,我们可以在枚举时开一个 b o o l bool bool数组记录重复即可。
- (敲黑板重点来了 对于本题来说,它的搜索分支非常的大,而最终状态却不会太大(序列长度 ≤ 10 \leq10 ≤10),于是我们可以限制搜索的深度,从1开始,如果大于当前的搜索深度立即退出,如果找到解则肯定是最优解退出即可。
- 这种限制搜索深度的方法就被称为迭代加深
c o d e code code
#include <cctype>
#include <cmath>
#include <complex>
#include <cstdio>
#include <cstring>
#include <deque>
#include <list>
#include <map>
#include <iomanip>
#include <queue>
#include <set>
#include <stack>
#include <string>
#include <vector>
#include <iostream>
#include <algorithm>
#include <functional>
using namespace std;
const int maxn = 110;
template <class T>
inline void read(T &s) {
s = 0;
T w = 1, ch = getchar();
while (!isdigit(ch)) { if (ch == '-') w = -1; ch = getchar(); }
while (isdigit(ch)) { s = (s << 1) + (s << 3) + (ch ^ 48); ch = getchar(); }
s *= w;
}
int n, idt;
int ans[maxn];
bool dfs(int k) {
if (k > idt) {
return ans[idt] == n ? true : false;
}
bool vis[105];
memset(vis, 0, sizeof(vis));
// memset(vis, false, sizeof(vis));
for (int i = k - 1; i >= 1; --i) {
for (int j = i; j >= 1; --j) {
if (ans[i] + ans[j] > n) continue;
if (vis[ans[i]+ans[j]]) continue;
if (ans[i] + ans[j] <= ans[k-1]) return false;
ans[k] = ans[i] + ans[j];
vis[ans[k]] = true;
if (dfs(k + 1)) return true;
}
}
return false;
}
int main() {
ans[1] = 1;
ans[2] = 2;
while (1) {
read(n);
if (!n) break;
if (n == 1) { puts("1"); continue; }
for (idt = 1; ; ++idt) {
if (dfs(2)) {
for (int i = 1; i <= idt; ++i)
printf("%d ", ans[i]);
puts("");
break;
}
}
}
return 0;
}