Algorithm 最大相交间隔

Algorithm 最大相交间隔,algorithm,data-structures,Algorithm,Data Structures,我手头有以下任务。我得到了N条规则,每个规则由3个区间组成 A1 B1 C1 D1 E1 F1 A2 B2 C2 D2 E2 F2 A3 B3 C3 D3 E3 F3 . . . 一个Bn Cn Dn En Fn 每个规则由三个不同的间隔组成[a、b][c、d][e、f] 让我们考虑包含三个值x、y和z的输入。如果a相交不是传递关系,则该输入将满足一个规则:如果a=[0,2],B=[1,3],C=[2,4],(a,B)和(B,C)相交,但不是(a,C)。所以答案是,一个点最多可以位于一个区

我手头有以下任务。我得到了N条规则,每个规则由3个区间组成

A1 B1 C1 D1 E1 F1
A2 B2 C2 D2 E2 F2
A3 B3 C3 D3 E3 F3
.
.
.

一个Bn Cn Dn En Fn

每个规则由三个不同的间隔组成[a、b][c、d][e、f]


让我们考虑包含三个值x、y和z的输入。如果a相交不是传递关系,则该输入将满足一个规则:如果a=[0,2],B=[1,3],C=[2,4],(a,B)和(B,C)相交,但不是(a,C)。所以答案是,一个点最多可以位于一个区间,即使B与两个相交

一个合适的暴力解决方案是计算规则所有子集的交集,并选择交集不为零的最大子集。但那将按O(2^N)的比例缩放


顺便说一句,这个问题被称为最大间隔刺伤问题(或其变体)。你可以在谷歌上找到它的参考。

你的方法是无效的,因为当规则1与规则2相交,规则1与规则3相交时,这并不意味着规则2与规则3相交

例如:

 Rule1:   [1,2] [3,4] [5,6]
 Rule2:   [1,1] [3,3] [5,5]
 Rule3:   [2,2] [4,4] [6,6]
在您的解决方案中,当您修复外部循环中的规则1时,然后在嵌套循环中查找规则2和规则3,并得到3的结果,而正确答案是2

我有一个可行的解决方案,但不是很有效:O(K3*N),其中K来自规则区间的定义域(K=max\u interval\u value-min\u interval\u value),N是规则的数量。它还消耗O(K*N)内存。如果这个设置符合问题的时间和内存限制,我可以描述我的解决方案,如果不是,我宁愿不要浪费时间

更新:

好了,开始吧。为简单起见,我将假设规则中出现的最小数是0,最大数是K。因此,只有K+1个可能的整数可以满足至少一个规则的间隔

由于每个规则正好有三个间隔,因此必须创建三个与这些间隔相对应的数组。索引
i
处的数组元素将包含一组规则,这些规则在相应的间隔中包括number
i
。每个数组的长度为K+1

例如,如果我们有规则:

 A: [1,2][3,4][5,6]
 B: [1,1][2,2][6,6]
 C: [2,2][4,4][5,5]
然后,第一个数组(对应于位置1处的间隔)将是:

第二个数组对应于第二个位置的间隔:

 0:{}, 1:{}, 2:{B}, 3:{A}, 4:{A, C}, 5:{}, 6:{}
第三个阵列将是:

 ...all empty... 5: {A, C}, 6: {A, B}
现在了解如何填充这些数组。从每个元素中的空集开始。然后你要遵守所有规则。对于每个规则,您将遍历位于相应间隔中的所有值,并将当前规则添加到适当的集合中。例如,对于第一个间隔的规则
A
,您需要迭代值1,2,并将
A
添加到索引1,2处的第一个数组中。这部分需要3*K*N个步骤(假设将元素添加到集合中是O(1))

接下来要做的基本上是尝试找出一个能够满足大多数规则的输入。您需要三个嵌套循环,例如,第一个间隔为
i
,第二个间隔为
j
,第三个间隔为
k
。您需要迭代从0到K的所有可能值。对于i,j,K的每个组合,您需要与三个集合相交,每个集合取自相应的数组。回到这个例子,对于i=2,j=4,k=5,你需要将{A,C}与{A,C}与{A,C}相交,这将得到最大的规则集。对于i=1,j=3,k=5,你将把{A,B}与{A}和{A,C}相交,只得到{A}。所以,您需要迭代,计算交集并找到最大的规则集。这部分的复杂性是O(K3*N),其中K3来自嵌套循环,N是集合交集的代价

就这些。我没有对这个解决方案考虑太多,所以可能它可以进一步优化。但至少它是多项式

更新

现在,如何消除一个嵌套循环

当您有一些
i
j
并且已经计算了前两个数组的组的交集时,您实际上得到了一个新任务。现在你们有了一组组,你们需要找到这个集合的最大子集,它只满足一个剩余的区间(第三个区间)。我建议迭代从0到K的所有可能值,并为每个值维护由该值满足的组集。为了做到这一点,您必须以两种方式对组的初始子集进行排序,第一种是按第一个区间的边界排序,第二种是按第二个区间的边界排序。让我们调用第一个排序数组
添加顺序
,第二个
删除顺序
。(稍后您会看到,为了简单起见,这些数组可以被队列替换)

如果初始子集中有三个组:

 A: [..][..][2,4]
 B: [..][..][2,2]
 C: [..][..][1,3]
它们的顺序如下:C、A、B用于
添加顺序

 C: [..][..][1,3]
 A: [..][..][2,4]
 B: [..][..][2,2]
B,C,A用于
删除订单

 B: [..][..][2,2]
 C: [..][..][1,3]
 A: [..][..][2,4]
循环中需要三个指针。第一个(
g\u add
)将指向(数组中的
add\u order
)您将要“添加”到维护集的组,第二个(
g\u remove
)将指向(数组中的
remove\u order
)您将要从维护集中删除的组。最后,
k
将保存当前值(从0到k)

返回示例,您将从0到5迭代
k
g_add
g_remove
最初指向对应数组的第一组):

如前所述,可以考虑<代码>删除命令>代码>代码> AddioOrthOuts<代码>作为队列,它们的头将相应地添加和删除候选。 现在谈谈复杂性。迭代所有对的

i
j
取O(K2)。现在,对于每一对这样的集合,你不需要对组进行排序,因为这可以在循环开始之前的一开始就完成。然后需要迭代
k
,添加和删除组。因为每个组只处理两次(添加和删除时),并且
k
是无效的
 B: [..][..][2,2]
 C: [..][..][1,3]
 A: [..][..][2,4]
 k=0, g_add=C, g_remove=B, res={} // nothing to do
 k=1, g_add=C, g_remove=B, res={} // `g_add` is pointing on the group whose first boundary is less or equal to `k`, adding this group to set of current groups, and incrementing `g_add`
 k=1, g_add=A, g_remove=B, res={C} // moving on, incrementing `k`
 k=2, g_add=A, g_remove=B, res={C} // now A satisfies adding condition
 k=2, g_add=B, g_remove=B, res={C, A} // B satisfies adding condition too
 k=2, g_add=, g_remove=B, res={C, A, B} // incrementing k (note that at that point we have largest set)
 k=3, g_add=, g_remove=B, res={C, A, B} // B has second boundary less than k, removing
 k=3, g_add=, g_remove=C, res={C, A} // B has second boundary less than k, removing
 k=3, g_add=, g_remove=C, res={C, A} // k++
 k=4, g_add=, g_remove=C, res={C, A} // C is suitable for removing
 k=4, g_add=, g_remove=A, res={A} // k++
 k=5, g_add=, g_remove=A, res={A} // A is suitable for removing
 k=5, g_add=, g_remove=, res={} // we are done
1,x,x,x,x,x
5,x,x,x,x,x
3,x,x,x,x,x
A_val = [ 1,5,3 ];
A_rule = [ 0, 1, 2 ];
A_val = [ 1,3,5 ];
A_rule = [ 0, 2, 1 ];
5,8,x,x,x,x
1,3,x,x,x,x
7,10,x,x,x,x
6,9,x,x,x,x
1,3,x,x,x,x
5,6,x,x,x,x

7,10,x,x,x,x
6,9,x,x,x,x
6,8,x,x,x,x