您的位置:首页 > 理论基础 > 数据结构算法

Python 数据结构与算法——从二分图到寻找最大排列(Maximum Permutation)

2016-03-21 16:43 190 查看
假设现在有 8 位有着特殊癖好的人去买票看电影,其中有一部分人得到了自己喜欢的座位,但大多数人并不满意。现在的问题是,如果这些人各自都有自己喜欢的座位(喜欢的座位有重叠,这是进行最大排列的前提,否则无法进行;座位有重叠,就必然存在一些无人愿去的座位,这恰是进行有效归纳的前提),那么我们希望给出某种交换座位的方式,以求让更多的人得到满意。

这其实是匹配问题的一种,我们其实可以将该问题(实例)模型化成某种图结构,如下图所示:



这其实是二分图(bipartite graph)的一个具体示例,这意味着在该图中,节点被分成了两个集合,而所有的边线都只存在于两个集合之间(边不存在于两个集合内部)。

问题分析归纳如下:

有没有座位是没有人想座的,也即上图中下排入度为 0 的点(b 和 g)?在一个有效的解决方案(一组排列)中,一个人(元素)最多只能被安排到一个既定座位上。也即不应该有空位,如果有空位的话,等于是让两个人做同一个座位。因此,移除空座位(包括对应的人)的做法不仅是对的,而且是必须的。对待上图,我们可以直接排除 b 和 g。问题得以归纳。

现在是时候将我们的归纳/递归算法转换为实际实现了。这种时候,往往要先解决实例中各对象如何表示(也即数据结构的选择)。就本例而言,我们可能会从图结构或能够反映图像之间映射关系的某个函数开始思考。本质上说,这里的映射关系只不过是各元素(0,…, n-1)与其位置(0,…,n-1)之间的关联性,我们使用 Python 中的列表(list)即可实现。例如,对于图,如果 a, b, c, d, e, f, g, h = range(8),我们就可做如下表示:

>>> a, b, c, d, e, f, g, h = range(8)
>>> M = [c, c, a, f, d, f, h, e]
>>> M[c]
0
# M 本质上是
# [2, 2, 0, 5, 3, 5, 7, 4]


接下来我们即可将这个递归算法的思路实现出来,尽管其查找淘汰元素的方式有些粗暴,也必然不会多有效率,但有时效率低下的实现也是一个良好的开始

def naive_max_perm(M, A=None):
if A is None:
A = set(range(len(M)))
if len(A) == 1: return A
B = set(M[i] for i in A)
C = A - B
if C:
A.remove(C.pop())
return naive_max_perm(M, A)
return A
>>> naive_max_perm(M)
{0, 2, 5}
# a、c、f 保留在排列中
# 而其他人不得不留在自己不喜欢的位置上
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: