我一直在努力解决我在下面提到的这个问题。我有一些想法,我尝试过。我首先选择了N个元组的所有组合并对它们进行排序,但实现起来很难看而且速度很慢。我认为这个问题有一种动态的编程方法。我在如何创建配置方面遇到了麻烦。在那之后,我想我知道如何解决这个问题。
问题陈述:
给定高度H(1 <= H <= 1,000,000,000),我们需要从N个元组中找到大于或等于H的高度序列。有几个条件: N个元组中的每一个都具有重量,高度和强度。 元组的强度表示可以在该元组之上的最大总权重。
问题是要求找到堆栈的最大安全值。安全值是可以在不超过任何较低元组强度的情况下添加的重量。如果不可能,只需打印-1。
INPUT:
第一行输入包含N和H.
接下来的N行输入描述了一个元组,给出了它的高度, 重量和力量。所有都是正整数,最多10亿。
示例输入:
4 10
9 4 1
3 3 5
5 5 10
4 4 5
示例输出:
2
答案 0 :(得分:9)
好吧,既然没有其他人发布过解决方案,我会对此进行分析。
鉴于两个元组t1 = (h1, w1, s1)
和t2 = (h2, w2, s2)
,我们可以将它们组合为任意一个
[t1 over t2]
或[t2 over t1]
。在每种情况下,我们都可以将结果视为另一个元组;例如,
t3 = [t1 over t2] = (h1 + h2, w1 + w2, min(s1, s2 - w1))
(得到的元组的强度不能高于组件元组的两个强度中的任何一个,并且底部元组的强度通过其顶部的元组的权重减小;所得到的强度可以是负的)。
无论组成的顺序如何,得到的元组的高度和重量都是相同的;但是,由此产生的强度可能因订单而异。我们对最大强度的元组感兴趣,因此我们采用两个可能值的最大值。鉴于上述情况,我们将组合定义为
t1 + t2 = (h1 + h2, w1 + w2, max(min(s1, s2 - w1), min(s2, s1 - w2)))
结果元组又可以与其他元组组合,依此类推。
我们需要的是找出所有高度元组的最大强度至少H
,因为问题中要求的最大安全值实际上是结果的强度元组。
因此,我们可以将起始最大强度设置为-1
,开始组合元组,并且每当我们找到一个高度H
或更高时,如果元组的强度更大,则更新当前最大强度。
规则1:结果元组的强度不能高于组件元组的两个强度中的任何一个,因此,在组成元组时,每当我们发现一个强度小于或等于当前max,我们可以丢弃它,因为它不是一个组件的元组可以具有高于当前最大值的强度。
规则1a:我们甚至可以丢弃用于更新当前最大强度的元组,因为这个问题不会向我们询问元组本身,只是最大值,以及该元组在任何其他组合中都不会产生任何更好的最大值。
规则2:现在,让我们采取自上而下的看法。任何n = 2k
元组的堆栈都可以看作由两个元组组成,每个元组由一堆k
元组组成;对于n = 2k + 1
,这两个堆栈的大小为k
和k + 1
。
所以我们按顺序构建:
依此类推,直到N
。在构建每个列表时,我们会根据上面的规则1 对其进行修剪。
规则1b:每当更新最大强度时,所有现有列表都应该修剪强度小于或等于新最大值的元组。无论何时在组成新元组时遇到这些元组,都可以立即或懒惰地完成。
就算法的描述而言,我认为就是这样。
在实现方面,我将实际元组存储为std::tuple
或struct
,并且扭曲:对于每个产生的元组,您需要存储它构建的主元组列表从;我会使用std::vector<std::size_t>
(包含第一个列表中主要元组的索引),因为您可以使用std::find_first_of
排除使用主要元组两次甚至更好的组合如果您对列表进行排序,std::set_intersection
。
对于每个级别的列表,std::vector
也是如此。
实际的C ++代码当然是你的工作。
注意:此处描述的算法具有非常糟糕的最坏情况复杂性特征。此解决方案的最坏情况意味着:大N
,大H
,与H
相比较小的元组高度,与其强度相比较小的元组权重。在这种情况下,上述规则中描述的修剪都不能直到很晚才开始,直到发生这种情况,我们才会发生组合爆炸。
然而,对于我认为更有趣的案例,更高的均匀度,权重和强度分布(类似于给出的例子),我认为这个解决方案会很好,即使与传统的动态编程相比也是如此解决方案,在这种情况下,它可能是整数背包解决方案的一部分,其中一个条件被反转(没有真正考虑过)。
我可能会在稍后回到这里,因为我只是出于好奇而有时间做一些实际的测量。