我有以下任务。我被赋予N个规则,每个规则由3个区间组成。
A1 B1 C1 D1 E1 F1
A2 B2 C2 D2 E2 F2
A3 B3 C3 D3 E3 F3
。
。
。
An Bn Cn Dn En Fn
每条规则由三个不同的区间组成,[a,b] [c,d] [e,f]。
让我们考虑包括三个值x,y和z的输入。如果< = x< = b且c< = y< = d且e< = z< = f,则该输入将满足规则。任务是找到可以通过任意输入满足的最大规则数的计数。
我试图用蛮力技术解决问题。它是O(N ^ 2)解决方案。我用每个其他规则检查每个规则,以查找它们是否相互交叉。我维护一个列表,其中记录了与当前规则相交的规则编号。我使用此记录输出最大大小。但是我使用这种方法得到了错误的答案。请通过提示我可能做错了什么来帮助我。
示例:
假设我们给出5条规则:
规则1:39 40 43 55 28 42
规则2:6 15 36 43 12 56
规则3:38 57 3 15 17 36
规则4:3 15 36 60 21 52
规则5:24 45 23 34 27 39
在这里,我们可以计算出只有规则2和规则4可以通过任何输入同时满足。因此,回答= 2.
答案 0 :(得分:1)
您的方法无效,因为当Rule1与Rule2相交且Rule1与Rule3相交时,这并不意味着Rule2与Rule3相交。
示例:
Rule1: [1,2] [3,4] [5,6]
Rule2: [1,1] [3,3] [5,5]
Rule3: [2,2] [4,4] [6,6]
在解决方案中,在外循环中修复Rule1,然后在嵌套循环中找到Rule2和Rule3,得到3的结果,而正确的答案是2。
我有一个工作解决方案,但效率不高:O(K 3 * N)其中K来自规则间隔定义的范围(K = max_interval_value - min_interval_value)和N是规则的数量。它还消耗O(K * N)内存。如果这个设置符合问题的时间和内存限制,我可以描述我的解决方案,如果没有,我宁愿不浪费我的时间。
<强>更新强>
好的,我们走了。为简单起见,我将假设规则中出现的最小数字为0,最大值为K.因此,只有K + 1个可能的整数可以满足至少一个规则的间隔。
由于每个规则只有三个间隔,因此您必须创建三个与这些间隔对应的数组。索引i
处的数组元素将包含在其相应间隔中包含数字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:{A,B}, 2:{A,C}, 3:{}.... rest are empty sets
第二个数组对应于第二个位置的间隔:
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(K 3 * N),其中K 3 来自嵌套循环,N是集合交集的成本。
这就是全部。我对这个解决方案没有多想,所以也许可以进一步优化。但至少它是多项式的。
<强>更新强>
现在如何消除一个嵌套循环。
当你有一些i
和j
并且已经计算了前两个数组的交集时,你几乎可以获得新的任务。现在你有了一组组,你需要找到这个集合的最大子集,它只能满足一个剩余的间隔(第三个)。我建议迭代从0到K的所有可能值,并为每个值维护该值满足的组的集合。为了做到这一点,你必须以两种方式对组的初始子集进行排序,首先是第一个区间的边界,第二个区间是第二个区间的边界。让我们调用第一个排序的数组add_order
,第二个remove_order
。 (稍后您会看到,为简单起见,这些数组可以替换为队列。)
如果初始子集中有三个组:
A: [..][..][2,4]
B: [..][..][2,2]
C: [..][..][1,3]
它们将按此命令:C {A},B add_order
。
C: [..][..][1,3]
A: [..][..][2,4]
B: [..][..][2,2]
和remove_order
的B,C,A:
B: [..][..][2,2]
C: [..][..][1,3]
A: [..][..][2,4]
循环中需要三个指针。首先(g_add
)将指向(在数组add_order
中)您将要“添加”到您维护的集合的组,第二个(g_remove
)将指向(数组{{1 }})您要从集合中删除的组。最后一个,remove_order
将保持当前值(从0到K)。
回到示例,您将从0到5迭代k
(k
和g_add
最初指向第一组相应的数组):
g_remove
正如我之前所说,您可以将 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
和remove_order
视为一个队列,他们的头脑将相应地添加和删除候选人。
现在关于复杂性。迭代所有add_order
和i
对取O(K 2 )。现在对于每个这样的对,你设置交集O(N),你不需要对组进行排序,因为这可以在循环之前的最开始时完成。然后,您需要迭代j
,添加和删除组。由于每个组仅处理两次(添加和删除时),k
从0到K迭代,因此该循环的复杂度为O(N + K)。
因此,对于整个算法,我们得到O(K 2 *(N + K)),考虑到K <&lt; N大致为O(K 2 * N)。
答案 1 :(得分:0)
相交不是传递关系:如果你有A = [0,2],B = [1,3],C = [2,4],(A,B)和(B,C)相交,但不是(A,C)。所以答案是一个点最多只能存在一个区间,即使B与两个区间相交。
一个合适的蛮力解决方案是计算规则的所有子集的交集,并选择具有非零交集的最大子集。但那会扩展为O(2 ^ N),然后。
顺便说一句,这个问题被称为最大间隔刺伤问题(或其某些变体)。您可以在Google上找到它的参考。
答案 2 :(得分:0)
我不完全确定你在问什么。我假设您想要一个给定任意输入x,y,z的算法,将输出匹配的规则计数。输出规则列表同样容易。
将规则集转换为每个值A,B,C,D,E,F的一对数组。因此,对于A的值,数组是A_val和A_rule。在A_val中,您放置了A的所有值,并在A_rule中放置了与这些值对应的所有规则索引。
E.g。如果你的规则是
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作为排序键对两个数组进行排序:
A_val = [ 1,3,5 ];
A_rule = [ 0, 2, 1 ];
对所有6个值执行此操作,因此您将拥有数组:A_val,B_val,C_val等以及A_rule,B_rule,C_rule等。
现在输入任何x,y,z,
对A_val进行二进制搜索,寻找x。从该索引到结尾,A_rule将包含A满足x的规则列表。
对B_val进行二进制搜索,寻找x。从该索引到B_rule数组的开头是B满足x的所有规则。
对6个间隔中的每个间隔执行此操作。您将拥有6组规则ID,它们满足6个条件中的每一个。现在只需找到这6组的交集。有一堆集交集算法。
请看这里:Efficient list intersection algorithm
一个简单的方法是将所有规则ID放入一个数组并对该数组进行排序。连续6次在排序数组中出现的任何规则id都是满足所有6个条件的规则。
答案 3 :(得分:0)
我想我误解了这个问题。在这种情况下,您可以通过二进制空间分区来解决此问题。
http://en.wikipedia.org/wiki/Binary_space_partitioning
将每个规则想象成定义立方体空间是有帮助的。 (我打赌他们这样做)随机选择规则,然后选择一个参数。使用该参数来划分空间。完全包含在分区一侧的所有规则都进入一个组,所有规则都在另一侧进入另一个组。如果规则是双方的,则将其放在两个组中,但将其参数调整为仅在一侧。
例如,规则:
5,8,x,x,x,x
1,3,x,x,x,x
7,10,x,x,x,x
6,9,x,x,x,x
您选择了规则3,参数A,值为6.将规则空间隔离:
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
因此规则0被分成两半,并放入两个空格。对每个组递归执行此过程,直到组中的所有规则相同为止。在每次递归中,按照以下顺序选择参数A C E B D F.即,您沿第一个约束划分空间,然后该空间中的下一个除法位于第二个约束等。
我不确定BSP宽度优先或深度优先是否更有效。当您找到一个空间以比任何先前空间更高的规则计数解析时,您可以停止递归具有那么多规则或更少规则的任何路径。 (.e.g如果我知道一个子空间有5个规则,如果我有一个未解决的空间有5个规则,我不必再做任何事了)
当您对所有空格进行分区直到它们各自具有相同的规则时,具有最多规则的分区是您的最大计数。