如何搜索每对符合标准的最大子集?

时间:2017-02-21 18:09:29

标签: algorithm search subset

我希望这不是一个统计问题...

假设我有一个界面:

public interface PairValidatable<T>
{
    public boolean isValidWith(T);
}

现在如果我有一个大型的PairValidatables数组,我怎样才能找到每个对通过isValidWith测试的那个数组的最大子集?

澄清一下,如果子集中有三个条目,那么元素0和1应该传递isValidWith,元素1和2应该传递isValidWith,元素0和2应该传递isValidWith。

实施例,

public class Point implements PairValidatable<Point>
{
    int x;
    int y;

    public Point(int xIn, int yIn)
    {
        x = xIn;
        y = yIn;
    }

    public boolean isValidWith(Point other)
    {
        //whichever has the greater x must have the lesser (or equal) y
        return x > other.x != y > other.y;
    }
}

The intuitive idea是保持点向量,添加数组元素0,并将每个剩余的数组元素与向量进行比较,如果它通过向量中的每个元素进行验证,如果是这样,则将其添加到向量中。 ..但问题是元素0可能非常严格。例如,

Point[] arr = new Point[5];
arr[0] = new Point(1000, 1000);
arr[1] = new Point(10, 10);
arr[2] = new Point(15, 7);
arr[3] = new Point(3, 6);
arr[4] = new Point(18, 6);

如上所述迭代将为我们提供仅包含元素0的子集,但是元素1,2和4的子集是更大的子集,其中每一对都通过验证。然后算法应该返回存储在元素1,2和4中的点。虽然元素3和4彼此有效并且元素1和4彼此有效,但元素2和3不是,元素1和3也不是。包含1,2和4的子集是比3和4更大的子集。

我猜一些树或图算法最适合解决这个问题,但我不确定如何设置它。

解决方案不必是特定于Java的,并且最好能够以任何语言实现,而不是依赖于Java内置函数。出于熟悉的原因,我上面只使用了类似Java的伪代码。

1 个答案:

答案 0 :(得分:5)

大概isValidWith是可交换的 - 也就是说,x.isValidWith(y)然后是y.isValidWith(x)。如果您只知道这一点,那么您将拥有maximum clique problem的实例,该实例已知为NP完全:

Skiena,S。S.“Clique and Independent Set”和“Clique”。算法设计手册中的§6.2.3和8.5.1。纽约:Springer-Verlag,第144和312-314页,1997年。

因此,如果你想要一个有效的算法,你将不得不希望你的特定isValidWith函数具有更多结构而不仅仅是交换性,你将不得不利用这种结构。

针对您的具体问题,您应该能够执行以下操作:

  1. 按x坐标的递增顺序对点进行排序。
  2. 在排序列表中找到y坐标的longest decreasing subsequence
  3. 每个操作都可以在O(n * log(n))时间内执行,因此您的特定问题可以有效解决。