我很久以来一直被this uva problem困住了。
含糊不清的问题陈述:给定一组不同长度的木棍,是否有可能将它们端到端地连接起来形成一个正方形?最多有20支,每支棒的长度小于10000。
此问题可能有不同的解决方案。其中一个是解释here的回溯解决方案。但是存在其他动态编程解决方案,解释here,here和here具有更好的运行时间。但我无法理解他们使用的是什么方法。请帮我理解dp算法。
答案 0 :(得分:3)
如果你不熟悉子集的动态编程,我建议你先阅读它。 This link可以提供帮助,但可能会有更好的教程。
回到给定的问题,因为M不超过20,所以下面的2 M ×M方法可能会有效。
对于给定木棍的2个 M 子集中的每一个,我们知道该子集中木棍的总长度。我们也知道所有给定的棒的总长度,因此也知道方形边的长度。我们通过在其两侧放置棍棒来构建广场。让我们来确定我们构建广场的顺序:我们从左上角开始,沿顺时针方向沿着方形边界移动,在路上铺设木棍,不留间隙。所以,首先我们完全构建上侧(从左到右),然后是右侧(自上而下),然后是下侧(从右到左),最后是左侧(自下而上)。每当我们遍历到下一个方角的距离为L时,我们就不能放置长度大于L的棒;至少直到我们用其他棍子到达那个角落。现在,问题是:我们可以通过我们的程序来构建方块吗?
有M!不同的订单我们可以尝试打好棍棒。但是,如果我们一个接一个地放置棍棒,在选择下一根棍子时,我们所关心的只是已经铺设的棍棒的 set ,而不是它们特定的顺序 。这个观察结果导致我们只考虑2个 M 子集,这个子集比M小!订单。
接下来,我们定义之前定义的问题的子问题。对于棍子的每个子集,问题是:我们可以按照上述程序的规则顺序铺设所有棍子的方式来订购棍棒吗?换句话说,我们可以构造方形遍历的“有效前缀”,如上所述吗?
如果上述问题的答案为“是”,我们会说棒的子集好,否则坏。当然,空子集是好。最后,我们感兴趣的是整套给定的棍棒是否也好。为了找到它,我们可以按自然顺序处理子集(对于M = 3,即000,001,010,011,100,101,110,111,其中1对应于子集中的棒)。对于每个新的非空子集S,它是好当且仅当它的一些“直接子集”T(没有恰好一个元素的S - 比如长度为X的棒)是好,根据我们施工程序的规则,T可以通过长度为X的长棍延伸(也就是说,铺设长度为X的棍子,我们不必在某个角落弯曲它)。
剩下的是实施细节。对于每个子集,要么存储或计算其中的棒的总长度,要找到到下一个角L的距离。如果这个子集是好的,它只能通过具有两个属性的棒来扩展:(1)长度不超过L和(2)尚未在子集中。