穷举查找
对于组合问题来说,穷举查找是一种简单的蛮力算法。它要求生成问题域中的每一个元素,选出其中满足问题约束的元素,然后再找出一个期望元素。
旅行商问题
简单来说,这个问题要求找出一条n个给定的城市间的最短路径,使我们在回到出发的城市之前,对每个城市都只访问一遍。这个问题可以很方便地用加权图来建模,也就是说,用图的顶点代表城市,用边的权重表示城市间的距离。这样该问题就可以表述为求一个图的最短哈密顿回路问题。
哈密顿回路:一个对图的每个顶点都只穿越一次的回路
对于四个点都连通的图,我们假定从a点出发,可以将获得(4-1)!条路径(公式(n-1)!),但是需要注意的是,如果没有假定起点,那么这个问题的规模将增大n倍
对于图中的例子,其实我们发现它们是两两成对的,同对之间不同的仅仅是方向,因此,我们可以将路径总数减半(n-1)!/2,但是,显然,这并没有提高太大的效率。
背包问题
这是计算机科学中另一个著名的问题。给定n个重量为
w
1
,
w
2
,
.
.
.
,
w
n
,
w_1,w_2,...,w_n,
w1,w2,...,wn,价值为
v
1
,
v
2
,
.
.
.
,
v
n
v_1,v_2,...,v_n
v1,v2,...,vn的物品和一个承重为W的背包,求这些物品中一个最优价值的子集,并且要能够装到背包中。
在这个问题中,穷举查找需要考虑给定的n个子集,为了找出可行的子集(也就是说,总重量不超过背包承重能力的子集),要计算出每个子集的总重量,然后在它们中间找到价值最大的子集。因为一个n元素集合的子集数量为
2
n
2^n
2n个,所以无论生成独立子集的效率有多高,穷举查找都会导致一个
Ω
(
2
n
)
\Omega(2^n)
Ω(2n)的算法。如下例子:
因此无论是对旅行商问题还是背包问题,穷举查找型算法对于任何输入都是非常低效的。实际上,这两个问题就是所谓的NP困难问题中最著名的例子。
分配问题
对于可以穷举查找求解的问题,我们再举第三个例子:有n个任务需要分配给n个人执行,一个任务对应一个人(意思是说:每个任务只分配一个人,每个人只分配一个任务)。对于每一对i,j=1,2,…,n来说,将第j个任务分配给第i个人的成本是C[i,j],该问题要找出总成本最小的分配方案。
下面是该问题的一个小规模的实例,表中的数值代表的是分配成本C[i,j]
很容易发现,分配问题的实例完全可以用它的成本矩阵C来表示。就这个矩阵来说,这个问题要求在矩阵的每一行中选出一个元素,这些元素分别属于不同的列,而且元素的和是最小的。请注意,求解该问题并没有一个显而易见的策略。例如,我们不能选择每行中的最小元素,因为这些元素可能属于同一列。实际上,整个矩阵的最小元素并不一定是最优解的一部分。下面是上面例子的答案:
由于在分配问题的一般情况下,需要考虑的排列数量是n!,所以除了该问题的一些规模非常小的实例,穷举查找法几乎不实用。幸运的是,对于该问题有一个效率高得多的算法,叫匈牙利方法。
笔者打算先把穷举的情况先了接了,再深入后面的改良,穷举算法的改进版后续会再做补充