问题“规范”:
这是圣诞节!你必须买礼物!
你有一套已经存在的玩具包,以及相应的捆绑价格:
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从“子集”更改为“严格子集”
X
是Y
X
比Y
目标是实现一个功能 bool isBadSubset(X)
,有效地发现X
是否合适。
鉴于有数百万个捆绑包,将它与每个捆绑包进行比较显然是不可行的。此外,您可以假设在现有的捆绑集合中,玩具的子集总是比超集便宜。
提示:
N
个玩具和更便宜。但是,列表可能仍然很大。挑战:是否有可能在不变的时间内实现这一目标? (独立于目前在集合中的捆绑数量)......或至少在log(n)中?
答案 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是否是一个糟糕的交易,您只需要记住该格子中的最少元素。基本方法:
您从一个空数据库开始。你逐个阅读矢量。对于每个向量,您可以根据数据库进行检查,看看它是否是一个糟糕的交易。如果是扔掉它,否则将其添加到您的数据库。这种方法的性能显然取决于您的数据。如果如你所说,玩具的数量是一个小的固定数字,那么你可能会很幸运。
如上所述,恒定时间是不可能的,原因很简单,因为您可能需要跟踪超常数量的元素,即使您对如何操作也很聪明。