UVA529 加成序列
传送门
题目分析
一道 dfs,迭代加深
我们可以很快的猜出来最终 \(m\) 的长度必然是小于 \(10\) 的。
而这种浅深度的问题正好适用于迭代加深。
之后考虑剪枝
优化搜索顺序 : 我们要让序列中的数字迅速地逼近 \(n\),自然是要 \(i\) 和 \(j\) 从大到小枚举,且 \(j<=i\)、
排除等效冗余 : 我们发现,对于不同的 \(i\) 和 \(j\) ,他们的 \(a[i]+a[j]\) 有一定的可能性会相同
所以避免重复搜索,我们需要进行判重.
好了,到这里你就可以轻松切掉《算法竞赛进阶指南》那个题了///
但是在 UVA 中,\(n\) 的数据范围可是 \(1e5\) 啊!
所以还有一个剪枝,
最优化剪枝 :后面每一项最多是前一项的 \(2\) 倍
代码实现
#include <bits/stdc++.h>
#define rint register int
#define endl '\n'
using namespace std;
const int N = 1e4 + 5;
int n, path[N];
bool dfs(int u, int k)
// u is the depth of now
// k is the depth of MAX
{
if (path[u - 1] > n)
{
return false;
}
if (u == k)
{
return path[u - 1] == n;
}
if (path[u - 1] * ((long long)1 << (k - u)) < n)//最优化剪枝
{
return false;
}
bool st[N] = {0};//通过 bool数组排除等效冗余
for (rint i = u - 1; i >= 0; i--)
{
for (rint j = i; j >= 0; j--)//搜索顺序
{
int s = path[i] + path[j];
if (s > n || s <= path[u - 1] || st[s])
{
continue;
}
st[s] = true;
path[u] = s;
if (dfs(u + 1, k))
{
return true;
}
}
}
return false;
}
signed main()
{
path[0] = 1;
while (cin >> n and n != 0)
{
int depth = 1;
while (!dfs(1, depth))// 不断扩大范围
{
depth++;
}
for (rint i = 0; i < depth - 1; i++)
{
cout << path[i] << " ";
}
cout << path[depth - 1];//UVA 输出不能有多余空格
puts("");
}
return 0;
}