寻找有效的算法(非平凡的)

时间:2011-09-11 09:53:12

标签: algorithm data-structures

问题“规范”:

这是圣诞节!你必须买礼物!

你有一套已经存在的玩具包,以及相应的捆绑价格:

1 0 0 1 0 1 1 1 0 => 58
0 1 0 0 1 1 1 0 0 => 27
1 1 1 0 0 0 1 0 0 => 46
0 0 0 0 1 1 1 1 0 => 73
...

1表示玩具在捆绑中,而0表示玩具不在捆绑中。

现在,圣诞老人宣传片即将到来,并以“特价促销价”向您提供剩余的捆绑X。如果存在另一个捆绑X,我们会说Y错误的协议,以便:{/ p>

编辑:为了更容易,我删除了条件3,但将条件1从“子集”更改为“严格子集”

  1. XY
  2. 严格子集
  3. XY
  4. 目标是实现一个功能 bool isBadSubset(X) ,有效地发现X是否合适。

    鉴于有数百万个捆绑包,将它与每个捆绑包进行比较显然是不可行的。此外,您可以假设在现有的捆绑集合中,玩具的子集总是比超集便宜。

    提示:

    • 比较一个集合是否是另一个集合的子集很容易
    • 可以限制比较设置,其中包含至少N个玩具更便宜。但是,列表可能仍然很大。
    • 筛子方向的东西会很好
    • 你不需要知道哪个捆绑更好......只是存在一个更好的

    挑战:是否有可能在不变的时间内实现这一目标? (独立于目前在集合中的捆绑数量)......或至少在log(n)中?

6 个答案:

答案 0 :(得分:3)

我设法找到一些关于快速搜索的相关文献,似乎在一般情况下你的问题并不容易。

Charikar, Indyk and Panigrahy (2002)研究子集查询问题:给定M个元素的某些宇宙U的N个子集的集合P和查询集Q,P中是否有一个集合是Q的超集?他们提出了两种算法,它们用于查询速度的存储空间交易。为了实现O(N / k)查询时间,他们需要在k的平方根中以指数因子的形式增加空间使用量。

Bevc and Sannik (2010)描述了一个简单的基于trie的子集查询数据结构,没有分析查询速度,但很明显它在存储集的数量N中是最坏情况线性的。

答案 1 :(得分:1)

我认为,在O(1)中寻求解决方案是不现实的。我能想到的唯一解决方案是生成一个完整的捆绑列表,并且每个捆绑包都表明它是否是一个好的...我怀疑这是你要求的。

简单的二进制搜索可能会很有趣,甚至没有详细说明玩具的细节,我们可以简单地指出价格和物品数量。如果存在另一个较低价格且较高数量的商品,则我们的商品是不良捆绑。

因此,我们可以定义一个键(price, nb items)并对它们进行有效排序。搜索将为O(n log n),然后对子集的包含测试仍将是线性的。

答案 2 :(得分:0)

好的,所以玩具的数量n是常数和小的,即你有{toy_0,.. toy_n-1}的集合。

然后你可以有一个数组Set[n] bundleContainingToy,如果bundle x包含toy_i,那么你将x保存在set bundleContainingToy [i]中。

如果你得到一个新的包1 0 0 1 0 1,你只需要计算交集bundleBtainingToy [0],bundleContainingToy [3]和bundleContainingToy [5]。如果交集是O(1)(您可以假设,因为您说检查子集属性是),那么您也可以在O(1)中执行此检查,因为n是常量(和小)。

这是你要找的筛子吗?其余的计算仅取决于包含toy_0,toy_3和toy_5的包的数量。

答案 3 :(得分:0)

如果要求查找部分应为O(1),则可以先构建地图:

map = {}
for (bundle, price) in bundles:
  for subset in subsets(bundle): #including bundle
    if map.contains(bundle)
      map[bundle] = min(map[bundle],price)
    else
      map[bundle] = price

现在检查这是不是很糟糕:

  def isBadDeal(bundle,price)
    return map[bundle] < price

答案 4 :(得分:0)

捆绑包和所有捆绑包之间的按位应标识哪些捆绑包包含捆绑包子集。接下来是不等式测试将返回是否存在包含该子集的更昂贵的集合。如果发现任何更昂贵的,那么捆绑是一件坏事。

在Python / numpy中:

import numpy

def bad_deal(bundle, cost):
    return ((bundles & bundle == bundle) * (prices < cost)).any()

# Generate some test data
numpy.random.seed(11)
global bundles, prices
bundles = numpy.random.randint(0,511,(1000000,)) # 000000000 to 111111111 
prices = numpy.random.randint(40,70, (1000000,)) # 40 to 70$

更好的解决方案是只保留捆绑包比先成本更便宜,然后检查捆绑包是否存在于该子集中,这意味着我们的交易很糟糕:

def bad_deal_2(bundle, cost):
    less_exp_bundles = numpy.delete(bundles, numpy.where(prices > cost))
    return (less_exp_bundles & bundle == bundle).any()

在这种情况下,最糟糕的情况是捆绑包是最昂贵的项目,而所有其他捆绑包都是它的超集,这需要检查所有捆绑包。在所有其他情况下,我们检查的是少于捆绑的总数。但是有必要检查所有价格(但是这个向量中的数据少于捆绑向量中的数据)所以首先检查价格更有意义,以减少我们需要检查的包的数量。

答案 5 :(得分:-1)

使向量成为不良交易的三个属性定义了一种关系。所有向量的幂集以及该关系定义了一个点阵。为了确定集合X是否是一个糟糕的交易,您只需要记住该格子中的最少元素。基本方法:

您从一个空数据库开始。你逐个阅读矢量。对于每个向量,您可以根据数据库进行检查,看看它是否是一个糟糕的交易。如果是扔掉它,否则将其添加到您的数据库。这种方法的性能显然取决于您的数据。如果如你所说,玩具的数量是一个小的固定数字,那么你可能会很幸运。

如上所述,恒定时间是不可能的,原因很简单,因为您可能需要跟踪超常数量的元素,即使您对如何操作也很聪明。