O(N * LogN)算法存在以下问题

时间:2011-05-06 13:38:25

标签: algorithm complexity-theory

存在以下问题:

  

一个城市最负盛名的体育俱乐部有N名成员。每个成员都很强大而且漂亮。更确切地说, i 这个俱乐部的成员(成员在他们进入俱乐部时被编号)具有力量S i 和美女B <子> I 。由于这是一个非常有声望的俱乐部,它的成员非常富有,因而非凡的人,所以他们经常非常讨厌彼此。严格地说, - 俱乐部成员X先生讨厌 j - 如果S < / sub>≤S j 和B i ≥B j 或者如果S i ≥S j 且B i ≤B j (如果X先生的两个属性都大于Y先生的相应属性,他甚至没有注意到他,另一方面如果他的两处房产都少了,他非常尊重Y先生。

     

为了庆祝新的2003年,俱乐部的管理部门正计划举办一个派对。然而,他们担心,如果两个互相仇恨的人同时参加聚会,喝了一两杯他们就会开始打架。所以不应该邀请两个互相仇恨的人。另一方面,为了保持俱乐部的声望达到适当的水平,政府希望邀请尽可能多的人。

     

作为唯一一个不怕触摸电脑的政府,你要编写一个程序,找出邀请参加聚会的人。

     

输入

     

*输入文件的第一行包含整数N - 俱乐部的成员数。 (2≤N≤100,000)。接下来N行包含两个数字 - S i 和B i (1≤S < em> i ,B i ≤109)。*

     

输出

     

在输出文件的第一行打印可以邀请参加聚会的最大人数。在第二行输出N个整数 - 以任意顺序邀请的成员数。如果存在多个解决方案,则输出任何一个。

     

样本测试

     

输入

  4
  1 1
  1 2
  2 1
  2 2
     

输出

  2
  1 4

我正在尝试解决问题但是我的算法的复杂性是O(N ^ 2)并且由于2 <= N <= 100000,因此需要改进算法。 我正在使用具有O(N ^ 2)复杂度的最长增加的子序列动态编程算法来解决该问题。 有人知道如何改进算法吗?

5 个答案:

答案 0 :(得分:2)

我认为你的O(n^2)解决方案甚至不正确,更不用说有效了。如果您有这样的事情:

3
2 2
1 1
3 3

答案是3.然而,经典的LIS算法会给出2。你有这个说明吗?

您可以做的是按S i 排序,并在{<1}}时间在B i 上应用LIS。为此,您可以使用段树或涉及二进制搜索的简单算法。如果您需要更多帮助,请告诉我。

总复杂度为O(n log n):此时可以进行排序,LIS也可以。

答案 1 :(得分:2)

这是一个O(n log(n))答案,其中包含了大量合理的详细信息。

首先按照美丽的上升,力量下降对人进行排序。消除重复。 (在这里明确地,或者通过在下一步中跳过它们来隐式地进行。)

浏览列表。当你走的时候,保持一个平衡的人群,他们可能正在成为最大上升链中的下一个人。每个人都应该存储当前链的长度,以及指向链中其余人的链表的指针。树应按强度分类。

更具体地说,每当你看到一个新人时,找到树中的下一个最弱的人(没人没事),并构建一个三元组(person, length of chain, pointer to chain)。将人员插入树中。如果树中的下一个更强的人的链不超过当前人,则删除该人。所有这些操作都是O(log(n))

当你完成所有人的处理后,树中的最大记录将有一个人在最大人链的末尾,链的长度和指向链表的指针与其余的链中的人。这是你的答案,打印出来。

为了向您展示您的样本数据,以下是您的开始:

4
1 1
1 2
2 1
2 2

这表示:

{person: 1, beauty: 1, strength: 1}
{person: 2, beauty: 2, strength: 1}
{person: 3, beauty: 1, strength: 2}
{person: 4, beauty: 2, strength: 2}

按美容增加排序,然后强度减少(没有重复)得到:

{person: 3, beauty: 1, strength: 2}
{person: 1, beauty: 1, strength: 1}
{person: 4, beauty: 2, strength: 2}
{person: 2, beauty: 2, strength: 1}

为了简化事情,我只用排序集代表树。这不是它应该如何在内存中表示。

插入人3后:

{person: 3, strength: 2, length: 1, next_person: null}

下一个人1个人3。

{person: 1, strength: 1, length: 1, next_person: null}

然后人4来到人1之后。(我把链表写成嵌套数据结构,实际上它应该是一个链表。)

{person: 1, strength: 1, length: 1, next_person: null}
{person: 4, strength: 2, length: 2, next_person: {person: 1, next_person: null}}

然后人2碰到了人。

{person: 2, strength: 1, length: 1, next_person: null}
{person: 4, strength: 2, length: 2, next_person: {person: 1, next_person: null}}

要找到你的答案,请看树的末尾,在第4个人,指向第1个人。你的答案是长度2,然后(从最好到最差)人4然后1。

答案 2 :(得分:1)

如果你想到一个以俱乐部成员为顶点并且“喜欢”为边缘的图形(即如果两个成员彼此讨厌,那么相应的顶点之间存在边缘),可以重新制定问题如下:

  

找到子集中所有顶点之间存在边的最大顶点子集。

事实上,所有顶点都有相互边的子集称为Clique或完整的子图。

如果无法利用图表的其他功能,请查找最大集团需要指数时间(请参阅this link)。本文建议使用Bron–Kerbosch algorithm

(S,B)平面中绘制成员,可以看到'like'边缘对应于从12点到3点之间以及6点到9点之间的方向从顶点出来的线条。很容易构造一个这样的边相交的例子,所以很遗憾不是平面图。

不幸的是,“喜欢”关系不是transitive,即A喜欢BB喜欢C这并不意味着{ {1}}也喜欢A(再次,这在C平面上很容易看到)。

答案 3 :(得分:0)

以下是btilly解决方案如何运作的一些论点:

  • 实际上,respectignore在某种意义上是对称的 如果A尊重B,那么B忽略A,所以这就足够了 仅查看其中一个关系,例如respect”。

  • 正如missingno所指出的,respect关系 是传递意义,如果A尊重B和B尊重C 然后A尊重C(以及B尊重的所有人)。

  • 考虑以下图表:顶点代表成员 从A到B的有向边意味着A尊重B(或等效地,B忽略A)。 在一个人消除重复之后(可以考虑 我们意识到,成员的重量对应于他们的多样性 没有周期(如果A尊重B,则B不可能 通过其他成员尊重A,在某些时候,人们必须这样做 有一个走向错误方向的边缘,即我们有一个 directed acyclic graph

  • 考虑图表中的路径:如果成员A在该路径上, 路径上的所有其他顶点要么被A尊重(进一步'下游') 或被A忽略(进一步'上游')。因此通过图表的任何路径 代表一群彼此都喜欢的成员。

  • 另一方面,如果A和B之间没有路径, 他们彼此讨厌(否则会有例如两者之间的直接边缘 它们)。

  • 所以我们重新解决了问题,找到了最长的路径 一个有向无环图(其中每条边有一个权重)可以完成 一旦我们构建了这样一个图表,就在线性时间内。

剩下的问题是比O(N ^ 2)更快地构造图形 即无需经过所有可能的顶点对。

以下是图形式的btilly示例(箭头表示respect):

example graph

  • 到达顶点A时,我们只需要添加“最近”的邻居 在某种意义上,即不是像我们可以通过他人达到的那些 比如B和C.

  • 这是排序在一个坐标中上升和下降的位置 在另一个坐标中来自:我们添加了边缘之后 A到B我们不会添加从A到D的直接边缘(因为去了 从A到D通过B或C更好),所以我们只需要 看看B的右边和下面的顶点(那些顶点) 不能有B)的优势

答案 4 :(得分:-1)

两个力量和美丽相同的人互相讨厌,力量和美丽的界限非常紧张......