UVA529 加成序列

传送门

题目分析

一道 dfs,迭代加深

我们可以很快的猜出来最终 \(m\) 的长度必然是小于 \(10\) 的。

而这种浅深度的问题正好适用于迭代加深。

之后考虑剪枝

优化搜索顺序 : 我们要让序列中的数字迅速地逼近 \(n\),自然是要 \(i\)\(j\) 从大到小枚举,且 \(j<=i\)

排除等效冗余 : 我们发现,对于不同的 \(i\)\(j\) ,他们的 \(a[i]+a[j]\) 有一定的可能性会相同

所以避免重复搜索,我们需要进行判重.

好了,到这里你就可以轻松切掉《算法竞赛进阶指南》那个题了///

AcWing 170

但是在 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;
}
posted @ 2022-08-06 15:06  PassName  阅读(37)  评论(0编辑  收藏  举报