目录
- 迭代加深
- 例题
- 加成序列
- 题意
- 思路
- 代码
迭代加深
搜索时可能会遇到这样一种情况:
明明答案就在第一层!但是因为DFS的缘故浪费很多时间
迭代加深就是用来解决这个问题的算法
定义一个 max_depth ,每次搜索时,超过这一层就全部剪掉、
(相当于我们划定一个区域,在这个区域内找解,如果找不到,再扩大区域)
?迭代加深和BFS有什么区别呢
BFS用队列存储,浪费空间,迭代加深本质是还是DFS,只存储本条路径,还是O(n)的算法
例题
加成序列
原题链接
满足如下条件的序列 X(序列中元素被标号为 1、2、3…m)被称为“加成序列”:
- X [ 1 ] = 1 X[1]=1 X[1]=1
- X [ m ] = n X[m]=n X[m]=n
- X [ 1 ] < X [ 2 ] < … < X [ m − 1 ] < X [ m ] X[1]<X[2]<…<X[m−1]<X[m] X[1]<X[2]<…<X[m−1]<X[m]
- 对于每个 k(2 ≤ k ≤ m)都存在两个整数 i 和 j (1 ≤ i , j ≤ k − 1,i 和 j 可相等),使得 X [ k ] = X [ i ] + X [ j ] X[k]=X[i]+X[j] X[k]=X[i]+X[j]。
你的任务是:给定一个整数 n,找出符合上述条件的长度 m 最小的“加成序列”。
如果有多个满足要求的答案,只需要找出任意一个可行解。
输入格式
输入包含多组测试用例。
每组测试用例占据一行,包含一个整数 n。
当输入为单行的 0 时,表示输入结束。
输出格式
对于每个测试用例,输出一个满足需求的整数序列,数字之间用空格隔开。
每个输出占一行。
数据范围
1 ≤ n ≤ 100
输入样例
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
题意
给出 n 构造一个序列,要求第一个数是1,最后一个数是n,严格递增,且后面的数一定要是前面两个数之和(两个数可以是同一个数),输出一个长度最小的序列
思路
序列的最小规模:1 2 4 8 16 32 64 128 此时就已经超过100了,说明正确答案的深度不会很深,适合用迭代加深来做
层数从1开始,依次考虑每一位选什么数字
优化:
- 优化搜索顺序:优先枚举较大的数,层数较少,更快的找到 n
- 排除等效冗余:举个栗子:1 2 3 4 现在枚举下一个数,不管选择1+4还是2+3结果都是5,就可以不用计算两次了(方法是开一个bool数组存储每个数是否被用过)
代码
#include <bits/stdc++.h>
using namespace std;
const int N = 110;
int n;
int path[N];
bool st[N]; // 标记某数是否被用过
bool dfs(int u, int depth) // 分别是当前层数和最大层数
{
if (u > depth) return false; // 当前层数>最大层数
if (path[u - 1] == n) return true; // 最后一个数为n满足条件
for (int i = u - 1; i >= 0; i -- )
for (int j = i; j >= 0; j -- )
{
int s = path[i] + path[j];
if (s > n || s <= path[u - 1] || st[s]) continue; // 大于最大值or小于前一个值or已被用过 都不满足条件
st[s] = true; // 标记s已被用过
path[u] = s; // 记录s
if (dfs(u + 1, depth)) return true; // 下一位
st[s] = false; // 恢复现场
}
return false;
}
int main()
{
path[0] = 1;
while (cin >> n, n)
{
memset(st, false, sizeof st);
int depth = 1;
while (!dfs(1, depth)) depth ++ ;
for (int i = 0; i < depth; i ++ ) cout << path[i] << ' ';
cout << '\n';
}
}