让人们坐在电影院里
Posted
技术标签:
【中文标题】让人们坐在电影院里【英文标题】:Seating people in a movie theater 【发布时间】:2011-12-12 19:09:53 【问题描述】:这是基于我读到的一篇关于大型软件公司提出的难题和面试问题的文章,但它有一个转折点......
一般问题:
在电影院中让人们直接坐在朋友旁边而不是敌人旁边的算法是什么。
技术问题:
给定一个 N × M 网格,用 N * M - 1 个项目填充网格。每个项目对于其他 N * M - 2 个项目都有一个关联布尔值。在 N 的每一行中,直接位于其他项目旁边的项目应该与其他项目具有正关联值。然而,列并不重要,即一个项目可以是它前面的项目的“敌人”。 注意:如果项目 A 对 B 具有正关联值,则这意味着 B 对 A 也具有正关联值。对于负关联值也一样。保证一个项目与至少一个其他项目具有正相关性。 另外,您可以在开始将它们放入网格之前访问所有项目及其关联值。
评论:
从昨天开始我一直在研究这个问题并思考它,从我发现它让我想起了 bin packing problem 并添加了一些要求。在一些空闲时间我试图实现它,但是一大群“敌人”坐在一起。我确信大多数情况下至少需要一对敌人并排坐着,但我的解决方案远非最佳。它实际上看起来好像我刚刚随机化了它。
就我的实现而言,我设置了 N = 10,M = 10,项目数 = 99,并且每个项目都有一个大小为 99 的数组,其中每个项目都有一个随机布尔值,表示友谊对应的项目编号。这意味着每个项目都有一个与他们自己对应的友谊值,我只是忽略了这个值。
我计划稍后再重新实现它,我将发布代码。谁能想出一个“好”的方法来减少敌人之间的座位冲突?
【问题讨论】:
它让我想起了电子元件的布局算法。我希望对其进行几次尝试,然后进行某种判断算法来选择“最佳”算法。这是我解决“放置”问题的一般方法,它非常适合迭代计算解决方案,而不是直接数值公式。 我认为是 .. 如果安德斯克想要手表让他坐在柱子后面或戴大帽子的人后面,因为它太冷而拒绝摘下它。 好无聊!让人们坐在座位上以最大化敌人之间的战斗会更令人兴奋。 这绝对是 NP-Hard,所以 - 这类问题没有已知的多项式解决方案,您是否也在寻找证明?或者您是否知道这一事实并在这些范围内寻找解决方案?你目前最好的解决方案是什么? 这个问题可能会在Mathematics 或Comp Sci Theory 找到更好的归宿,因为它与编程无关。 【参考方案1】:这个问题是NP-Hard。
定义L=(G,n,m)|there is a legal seating for G in m×m matrix,(u,v) in E if u is friend of v
L 是这个问题作为语言的正式定义。
证明: 我们将分两步显示 Hamiltonian-Problem ≤ (p) 2-path ≤ (p) This-problem [Hamiltonian and 2-path defined below],因此我们得出结论这个问题是 NP-Hard .
(1) 我们将证明在不使用任何顶点两次的情况下找到两条覆盖所有顶点的路径是 NP-Hard [让我们称这样的路径:2-path 而这个问题为 2-path 问题] 从Hamiltonian Path problem 减少:
input: a graph G=(V,E)
Output: a graph G'=(V',E) where V' = V U u₀.
正确性:
如果 G 具有哈密顿路径:v₁→v₂→...→vn,则 G' 具有 2 路径: v₁→v₂→...→vn,u₀ 如果 G' 有 2 条路径,由于 u₀ 与其余顶点隔离,因此存在 路径:v₁→...→vn,即 G 中的哈密顿量。因此:G 有哈密顿路径 1 ⇔ G' 有 2-path,因此:2-path 问题是 NP-Hard。
(2)我们现在将证明我们的问题 [L] 也是 NP-Hard: 我们将展示上面定义的 2 路径问题的简化。
input: a graph G=(V,E)
output: (G,|V|+1,1) [a long row with |V|+1 sits].
正确性:
如果 G 有 2 条路径,那么我们可以让人们坐下,并使用 1 坐间隙 用作两条路径之间的“缓冲区”,这将是一个合法的完美座位 因为如果 v₁ 在 v₂ 旁边,那么 v₁ v₁→v₂ 在路径中,因此 (v₁,v₂) 在 E 中,所以 v₁,v₂ 是朋友。 如果 (G,|V|+1,1) 是合法席位:[v₁,...,vk,buffer,vk+1,...,vn] ,则有G中的2路径, v₁→...→vk, vk+1→...→vn结论:这个问题是NP-Hard,所以没有已知的多项式解。
指数解: 您可能想使用backtracking 解决方案:基本上是:创建大小为 |V|-2 或更小的 E 的所有子集,检查哪个最好。
static best <- infinity
least_enemies(G,used):
if |used| <= |V|-2:
val <- evaluate(used)
best <- min(best,val)
if |used| == |V|-2:
return
for each edge e in E-used: //E without used
least_enemies(G,used + e)
在这里,我们假设 evaluate(used) 给出了这个解决方案的“分数”。如果这个解决方案是完全非法的[即一个顶点出现两次],evaluate(used)=infinity
。当然可以进行优化,修剪这些情况。为了获得实际坐姿,我们可以存储当前最佳解决方案。
(*)可能有更好的解决方案,这只是一个简单的可能解决方案,这个答案的主要目的是证明这个问题是 NP-Hard。
编辑:更简单的解决方案:
创建一个图G'=(V U u₀ ,E U (u₀,v),(v,u₀) | for each v in V)
[u₀ 是缓冲区的垃圾顶点] 和边的权重函数:
w((u,v)) = 1 u is friend of v
w((u,v)) = 2 u is an enemy v
w((u0,v)) = w ((v,u0)) = 0
现在你得到了一个经典的TSP,它可以是solved in O(|V|^2 * 2^|V|)
使用动态编程。
请注意,此解决方案 [使用 TSP] 适用于一个内衬剧院,但它可能是为一般情况找到解决方案的好方法。
【讨论】:
【参考方案2】:用于大型“搜索空间”的一种算法是simulated annealing
【讨论】:
以上是关于让人们坐在电影院里的主要内容,如果未能解决你的问题,请参考以下文章