【问题标题】:LIS for coordinate values in O(NlogN) or O(Nlog^2N)LIS 用于 O(NlogN) 或 O(Nlog^2N) 中的坐标值
【发布时间】:2017-05-22 19:39:59
【问题描述】:

这是一道标准的动态规划题LIS PROBLEM

我想要二维坐标中点的最长递增子序列

也就是说,数组中索引 i 处的 2 个点 A(x1,y1),数组中索引 j 处的 B(x2,y2) 可以是递增序列的一部分,如果 (x1i)

我的代码如下,使用标准 DP 为 O(N^2) :-

#include <vector>
#include <iostream>
#include <algorithm>


using namespace std;


struct Pair
{
    int x;
    int y;
};



int main()
{

    int n;
    cin>>n;

    vector<Pair> arr;
    int L[1000000];

    Pair a;

    int i;int Maxchain=0;
    for(i=0;i<n;i++)
    {

        cin>>a.x>>a.y;
        arr.push_back(a);

        L[i]=0;
        for (int j = i-1; j >=0; j--)
        {

            if ((L[j]>(Maxchain-1))&&(L[j]>=L[i])&&(arr[j].x <= arr[i].x) && (arr[j].y <= arr[i].y) && !(arr[j].x == arr[i].x && arr[j].y == arr[i].y))
                L[i] = L[j]+1;


        }

                Maxchain = L[i]>Maxchain ?L[i]:Maxchain ;

    }
    cout<<Maxchain;

    return 0;
}

这是一个 O(N^2) 的解决方案,是否可以进一步简化或任何算法来解决 O(NlogN) 或 O(Nlog^2N) ?

在这里找到一些东西供参考:

Longest Increasing Subsequence (LIS) with two numbers

第二个答案更适合我的情况,但我们如何实施呢?

需要更好的答案或算法。

【问题讨论】:

  • 您引用的维基百科文章显示了O(n log n) 算法。它不适合你吗?
  • 不是一维@IgorTandetnik
  • 据我了解,您确实有一个一维数组,其中包含可以相互比较的元素。每个对象内部由一对数字组成的事实是无关紧要的。算法中没有任何内容要求对象是整数或其他标量类型 - 只是它们具有可比性。
  • 如果您考虑充分,您就会明白决定在 LIS 中选择哪个元素是困难的,就好像我不选择一个元素一样,在某些情况下它可能是 LIS 的一部分,但我知道那里是一个复杂度低于 O(N^2) 的解决方案。
  • 如果你有 2 个变量,它已经是二维的,因为它们是坐标。检查 THis Link 但选择的答案是错误的,第二个位置是正确的,但我需要在 C++ 中实现以我的条件。最近发现。

标签: c++ algorithm c++11 dynamic-programming lis


【解决方案1】:

我假设两个坐标都在[0..N-1] 范围内(如果不是这样,我们可以“压缩”它们而不改变它们的顺序关系)。

让我们仔细看看标准的动态规划解决方案。设f[i] 是在i-th 位置结束的最长递增子序列的长度。一种简单(但缓慢)的计算方法过于迭代所有先前的元素并选择最佳元素。我们想要找到的是max f[j] 用于所有这些jp[j].x &lt;= p[i].xp[j].y &lt;= p[j].y。它看起来像是矩形中的某种二维查询(我知道还有另一个条件 p[j] != p[i],但我们可以通过查询两个矩形 (p[i].x - 1, p[i].y)(p[i].x, p[i].y - 1) 来解决它。)。

所以我们需要一个支持两种操作的数据结构:添加具有特定值的点和获取矩形中的最大值。通过 x 坐标存储平衡二叉搜索树的 x 坐标分段树在其范围内的所有点可以在 O(log^2 N) 中执行每个查询。每个查询范围在树中最多分解为O(log N) 个节点。如果是插入查询,我们需要将当前点(p[i].x, p[i].y) 与值f[i] 插入到每个节点的二叉搜索树中。如果它是获取最大查询,我们需要为这些树中的每一个的某些前缀获取最大值。无论哪种方式,我们对每个查询的O(log N) 二叉搜索树执行O(log N) 操作。因此,总时间复杂度为(N * log^2 N)。空间复杂度为O(N log N),因为树中有O(log N) 层,每个点在每个层中最多出现一次。

此解决方案已满足您的要求,但看起来很难编码。我们可以稍微简化一下。我们可以进行两次“运行”:在第一次运行期间,我们只存储进入分段树每个节点的查询(到目前为止,我们没有存储任何额外的信息)。现在我们可以保留节点中出现的所有数字的向量和相同长度的二叉索引树,以跟踪每个前缀的最小值并有效地获取它(大图:我们使用了我们知道所有事先查询,所以我们可以使用排序向量和二叉索引树的组合,而不是二叉搜索)。时间和空间复杂度分析同上。

简短回顾:我们使用了一种数据结构,该结构支持矩形中的最大查询和有效插入新点,以加快在O(N^2) 动态编程解决方案中为固定i 找到最佳jO(N log^2 N) 中解决它。

【讨论】:

  • 可以提供demo吗?
  • @VenuKantSahu 我没有解决这个问题的代码。这是一个链接:topcoder.com/community/data-science/data-science-tutorials/…,它解释了如何构建和使用段树。您只需要存储向量和二叉索引树,而不仅仅是每个节点中的最小值。
  • 1
  • @VenuKantSahu 正如我在回答开头所说的那样,我们可以在不更改顺序的情况下分别压缩xy,以便它们都进入[0, N - 1] 范围。跨度>
  • 找到SPOJ problem 和它的解决方案在这里solution 几乎相同的问题:) 你明白这段代码吗?
猜你喜欢
  • 2014-11-04
  • 1970-01-01
  • 2021-10-22
  • 1970-01-01
  • 1970-01-01
  • 2013-02-03
  • 1970-01-01
  • 1970-01-01
  • 2018-05-26
相关资源
最近更新 更多