查找满足特定条件的集合的元素的所有组合

时间:2013-05-11 07:50:03

标签: algorithm

这是我试图解决的问题: 我给了一组斜率为m且常数为c的线。现在我需要找到在y轴右侧相交的这些线的交点数。这基本上意味着对于第1行和第2行

                    c1>c2 and m2>m1

我需要一个O(nlogn)算法来计算y轴右侧的交叉点总数(如果算法存在)。我总是可以通过蛮力来获得o(n2)算法,但我正在寻找更快的算法。

3 个答案:

答案 0 :(得分:3)

两个排序的矢量会做到这一点。

  1. 将所有行推入向量v1。
  2. 按常数c排序v1。之后,v1 [0]是具有最小c的行。
  3. 从头到尾遍历v1。对于v1中的每个元素e,我们应该只考虑之前访问过的元素(c1> c2)。现在的任务是在所有被访问元素中找到m2> 1的元素。 M1。
  4. 所以我们只是将已经访问过的元素推送到向量v2中。我们应该在每次插入后按斜率m对其进行排序(自平衡BST将执行此任务)。由于v2按m排序,因此二进制搜索将告诉您有多少元素满足m2> m1。
  5. 排序是n log n。

    插入到v2是log n(可以通过自平衡BST实现,它将调用n次)。

    二进制搜索是log n(调用n次)。

    所以它是O(nlog n)

    如果你用C ++写这个,那就像那样(我没有定义v2,因为你将实现自我平衡BST ):

    struct line
    {
        int c,m;
        line(int a,int b):c(a),m(b){}
        bool operator <(const line &a) const
        {
            return m>a.m;
        }
    };
    bool cmp(const line &v1,const line &v2)
    {
        return v1.c<v2.c;
    }
    int main()
    {
        vector<line> v1;
        v1.push_back(line(1,3));
        v1.push_back(line(4,1));
        v1.push_back(line(3,1));
        v1.push_back(line(2,2));
        sort(v1.begin(),v1.end(),cmp);
        int ans=0;
        for(int i=0;i<v1.size();i++)
        {
            int num=v2.find(v1[i]);//return the number of element whose m is larger than  v1[i].
            ans+=num;
            v2.insert(v1[i]);// in every step, the element e in v2 will satisfy e.c<v1[i].c
        }
        cout << ans;
    }
    

    这就是全部。如果您有任何疑问,请发表评论。

答案 1 :(得分:0)

我发布了我的解决方案,因为我认为实施起来更简单:

假设你有Line的对象,并定义了以下属性:

- m (slope,    initialized on start)
- c (constant, initialized on start) 
- pos_m ( default 0 value )
- pos_c ( default 0 value )

现在,您有这些行的V向量,然后:

  1. 使用元素(O(nlogn))上的键Vm进行排序。
  2. V集合i(O(n))上迭代V[i].pos_m = i
  3. 使用元素(O(nlogn))上的键Vc进行排序。
  4. V集合i上对V[i].pos_c = i进行迭代。 (O(N))。
  5. result = 0现在迭代V索引i执行result += | V[i].pos_m - V[i].pos_c |(O(n))
  6. 在排序时,如果比较值相等,则使用另一个键来确定顺序(如果两者相等,则它们是同一行)。例如,如果在1.两条线具有相同的斜率,则将常量设为决策者。

答案 2 :(得分:-1)

在最坏的情况下,这个问题保证需要O(n ^ 2)次操作。

假设我画了一条线,那么就没有交叉点。我可以在一个独特的点画一条与该线相交的线。我现在可以绘制一条与前两行相交的线。我可以继续绘制与前一行相交的线条。

这意味着交叉点的数量可以达到:

1 + 2 + 3 + 4 + 5 + ... + n-1

如果输入大小为n的行,则此问题的输出大小可以是(N *(N-1))/ 2个点或大约N平方在2以上。

因此,即使只输出正确的答案,在最坏的情况下也需要O(n ^ 2)。

编辑,忽略前一个,我以为你想要实际的交点,而不仅仅是计数。