在某些约束下找到项目的最佳组合的算法

时间:2012-01-10 08:08:51

标签: algorithm

我会尝试用数学语言解释这个问题 假设我有一组项X = {x_1, x_2, ..., x_n}X的每个项目都属于其中一个集合S_1, S_2, ..., S_5。我认为X的所有子集都包含5个项目: {x_i1, x_i2, ..., xi5}因此x_i1属于S_1,......,x_i5属于S_5
一些子集被认为是正确的,一些被认为是不正确的。如果子集不包含冲突项,则认为该子集是正确的。我有一个函数f1来判断一对项目是否冲突 我还有一个函数f2,它可以比较这些正确的子集,并说出哪个子集更好(它们可能也相同)。
我需要找到最好的不冲突的子集。

Algo我用过:
我构建了所有子集,丢弃了不正确的子集。然后我使用f2作为排序函数对正确的子集进行了排序,并采用了第一个最佳子集(我使用了快速排序算法)。只要存在大量子集,此过程就会花费不足的时间。

在时间消耗方面有更好的方法吗?

已更新
让我们将x_i看作是整数端点的间隔。如果2个间隔不相交,则f1返回true,否则返回false。 f2比较子集中间隔的总长度。

7 个答案:

答案 0 :(得分:1)

如果没有进一步限定域和评估函数,可以通过将SAT减少到它来轻松地将此问题显示为NP-Complete(即,如果S_1,...,S_5为{true,false},则f2 = 1公式为fullfiled,如果不是则为0)。因此,在这种情况下,即使不考虑f1,你也没有运气。

如果您对f1和f1的实际结构有更多了解,那么您可能会有更多的运气。看看Constrait Satisfaction Problems,找出f1和f2结构中要查找的内容。

答案 1 :(得分:1)

  

让我们将x_i看作是整数端点的间隔。如果2个间隔不相交,则f1返回true,否则返回false。 f2比较子集中间隔的总长度。

如果我理解正确,这意味着我们可以从X为每个x_i分配一个值(它的长度)。那么就不需要在每个可能的解决方案/子集上评估f2。

最小的5 x_i不太可能构成最佳子集。根据实际数据,最佳子集可能是5个最大间隔。所以我建议按值排序X.一般的想法是从最高的x开始并尝试添加更多的x(最高的第一个)直到你有5个非重叠。在产生所有可能子集的一小部分(当然取决于具体问题)之前,您很可能会找到最佳子集。但在最坏的情况下,这并不比你的解决方案快。

答案 2 :(得分:1)

如果我们将条件从每个S_i中取出一个x,则此问题等效于区间图中的最大权重独立集(即,在顶点中的图中查找成对未连接顶点的最大权重集表示间隔,如果相应的间隔重叠,则连接顶点)。这个问题可以在多项式时间内解决。这里的版本也有每个顶点的颜色,所选的顶点需要具有所有不同的颜色。我不知道如何在多项式时间内解决这个问题,但你可以利用没有太多颜色的事实:制作一个动态编程表T [C,x],其中C是一组颜色,x是位置间隔的终点。 T [C,x]应包含您可以从| C |获得的最大权重C中颜色的间隔位于x的左侧。然后,您可以从左到右填写表格。这应该是可行的,因为只有2 ^ 5 = 32个颜色集。

答案 3 :(得分:1)

如果我对你的问题的理解是正确的,我有一个应该是好的解决方案: 所以我从我理解的开始

each Integer is actually an interval from I1 to I2 and a Set is a 
combination of such intervals. A Set is correct if none of the intervals 
are intersecting and Set1>Set2 if the sum of Intervals in S1> sum of Intervals in S2.

所以我在这种情况下所做的就是这些方面的事情。

  1. 在比较间隔以确定它们是否相交时,请执行此操作。

    a)按起点顺序对间隔进行排序

    b)比较连续间隔的第一个终点和起始点的终点以确定重叠。保持一个名为gap的整数,如果2个区间的开始和结束不与它们的差异重叠增量差距。

  2. 这将通过执行Endpoint(lastI)-Startpoint(firstI) - Gap自动获得集合中的间隔总和。

    =>如果你只需要最好的,你可以拿一个变量max并保持比较集合。

    =>如果您需要top5或其他内容,请按照以下步骤操作,否则请跳过。

    1. 只要得到总和并且设置正确,就将总和添加到5个元素的“MinHeap”中。前5个元素将按原样运行。基本上你正在跟踪前5个元素。当一个新集合小于堆的最小值“Do Nothing并忽略此集合,因为它小于前5个集合”时,当集合大于min(意味着它在前5个中)时替换min然后将元素向下筛选,将前5的最小值保持在顶部。这将始终保持堆中的前5个元素。

    2. 现在您已经拥有前5个元素,您可以通过5个弹出轻松确定最佳元素。 :)

    3. 注意:如果区间是随机顺序,它将进入O(n ^ 2)解决方案,然后每个比较将再次有4个if语句来检查重叠位置。您可以在O(nlogn)中对间隔进行排序,然后通过列表一次以确定重叠(nlogn + n = nlogn),同时获得前5个集合。这可以改善您的表现和时间。

答案 4 :(得分:1)

此问题是最大加权区间调度算法的变体。 DP算法的多项式复杂度为O(N*log(N))O(N)空间用于天真问题,O(2^G * N * logn(N))复杂度为O(2^G * N)空间用于此变异问题,其中GN表示组/子集的总数(此处为5)&间隔分别。

如果x_i不表示间隔,则问题出在NP中,其他解决方案已经证明了这一点。

首先让我解释一下最大加权区间调度的动态规划解决方案,然后解决变异问题。

  • 我们获得了开始&间隔的结束点。让start(i)end(i)weight(i)分别为间隔i的起点,终点,间隔长度。
  • 根据起点的增加顺序对间隔进行排序。
  • 让间隔的排序顺序为1, 2, ... N
  • next(i)代表与区间i不重叠的下一个区间。
  • 让我们将子问题S(i)定义为仅考虑作业i, i+1, ... N的最大加权间隔。
  • S(1)是解决方案,它会考虑来自1,2,... N的所有作业并返回最大加权间隔。
  • 现在让我们递归定义{{​​1}}。

S(i)

此解决方案的复杂性为S(i) = weight(i) if(i==N) // last job = max(weight(i)+S(next(i)), S(i+1) O(N*log(N) + N)用于查找所有作业的N*log(N)next(i)用于解决子问题。空间为N,用于保存子问题解决方案。

现在,让我们解决这个问题的变化。

  • 让我们集体查看X中的所有区间。每个区间属于一组S_1,... S_5。
  • O(N)start(i)end(i)weight(i)分别为间隔subset(i)的起点,终点,间隔长度,子集。
  • 根据起点的增加顺序对间隔进行排序。
  • 让间隔的排序顺序为i
  • 1, 2, ... N代表与区间next(i)不重叠的下一个区间。
  • 让我们将子问题i定义为最大加权区间,只考虑作业S(i, pending)i, i+1, ... N是一个子集列表,我们必须从中选择一个区间。
  • pending是解决方案,它会考虑所有作业S(1, {S_1,...S_5}),为每个1,...N选择一个时间间隔并返回最大加权时间间隔。
  • 现在让我们按照以下方式递归定义{{​​1}}。

S_1,...S_5

请注意,我可能错过了一些基本情况。

此算法的复杂性为S(i)S(i, pending) = 0 if(pending==empty_set) // possible combination = -inf if(i==N && pending!={group(i)}) // incorrect combination = S(i+1, pending) if(group(i) not element of pending) = max(weight(i)+S(next(i), pending-group(i)), S(i+1, pending) 空间。 O(2^G * N * logn(N))表示子问题的大小。

作为估算,对于O(2^G * N)的较小值和2^G * N的较高值,此算法运行得非常快。对于中等值G<=10N>=100000也应该低,以使此算法收敛。对于G>=20的高值,算法不会收敛。

答案 5 :(得分:0)

我没有得到答案,因为你提出了非常抽象的问题,但我会给你一个想法。

尝试思考multiThreading。例如,您可以使用有限数量的线程创建线程池。然后找到一个递归解决方案,并在你潜入时为每个循环开始新的任务。

我说,因为你可以将这个问题分解为许多小任务,因为你的算法会更好。

在数学上思考问题!

答案 6 :(得分:0)

考虑使用查找表来优化f1的时间。考虑将您发现的子集插入到合并排序列表中,而不是最后快速排序。如果域很小且有限,则可以通过填充稀疏数组来实现一些非常快速的合并排序。