USING INDUCTION TO DESIGN 使用归纳法设计算法 [5/14]

接上文:http://blog.csdn.net/jj12345jj198999/article/details/6607832

 

选定I为所有线段中具有最大左端点值的线段,由于其他线段左端点值都较之小,这样就不需要再检查左端点值了。因此,为了要检查I是否包含于其他线段之中,我们只需要检查其他线段中是否有右端点值比I右端点值更大的线段。为了找到这么一条具有最大左端点值的线段我们可以依据线段的左端点值对所有线段进行排序并且按照次序对其进行搜索。假定线段已经按照次序排好,L1≤L2≤...≤Ln。归纳假设如下:

归纳假设:我们已经知道如何去解决包含I1,I2...In-1条线段的问题。

最基本的问题很简单,如果只有一条线段,那么它肯定不会被标记。现在我们来考虑In。通过归纳假设我们知道已经确定了在线段I1到In-1中有哪些线段是包含在其他线段之中的,我们需要确定In是否包含其他(之前没有被标记过)的线段,以及In是否被包含在其他线段之中。让我们首先来检查In是否被包含在其他线段之中。如果In被包含在一条线段中,假如是Ij,j<n,于是Rj≥Rn。这是唯一的必要条件(因为排序已经确保了Lj≤Ln)。因此我们只需要在之前的线段中记录拥有的最大右端点值即可。把该右端点值与Rn进行比较就能给出我们答案。我们稍微改变一下归纳假设:

更强的归纳假设:我们已经知道如何解决I1,I2...In-1的问题,同时也找出了他们中右端点的最大值。

我们再一次让In作为拥有最大左端点值的线段,然后让MaxR作为前n-1条线段中右端点的最大值。如果MaxR≥Rn,那么In就应该被标记,否则(MaxR≤Rn)Rn就成为新的最大的最大值。(这最后一步是必要的,因为我们现在不仅仅是标记线段,同时我们也在寻找最大的右端点值。)我们现在仅通过一步检查就能确定In的状态。

为了完成这个算法我们需要检查In是否包含一条之前未被标记过的线段。In包含一条线段Ij,j<n,只有当满足条件Lj=Ln且Rj<Rn时才行。我们可以通过增强排序功能来处理这种情况。现在我们不仅按照左端点值进行排序,同时对于具有相同左端点值的线段,我们依据他们的右端点值的逆序来进行排序。这样能够排除上面提到的情况出现,因为Ij将会放置在In之后(右端点值较小),而且Ij的包含性将会被上一个算法找到。完整的算法如下所示:

线段包含性算法
(I1,I2,...In:线段)
{用一对Lj,Rj来给出一条线段Ij}
{我们假定没有两条线段是完全一样的}
{当Ij被包含在另一条线段中时,Mark[j]将会被标记为真}

begin
 按照线段的左端点值递增次序对所有线段进行排序
 具有相同左端点值的线段按照他们右端点值递减的次序进行排序
 {for all j<k either Lj<Lk or Lj=Lk and Rj>Rk}
 MaxR:=R1;
 for j:=2 to n do
   if Rj≤MaxR then
      Mark[j]:=true;
   else
      Mark[j]:=false;
      MaxR:=Rj;
end;

复杂性:除了排序外,这个算法包含一个涉及到O(n)步操作的循环。由于排序需要O(nlogn)步操作,故其占据了算法主要的运行时间。

总结:这个例子阐明了一个不是那么直接运用归纳法的方法。首先我们选择可以运用归纳法执行的序列。然后我们设计归纳假设,该假设能够暗示出期望的结果同时它也易拓展。重点放在这些步骤上就能让对很多算法的设计变得简单。

 

明智的选择归纳序列

在前面的例子中,重点都放在寻找一个缩减问题规模的算法上。这是使用归纳法的本质。然而有很多方法也能实现这一点。首先,问题可能包含一些参数(例如图中的左端点右端点,顶点和边),我们必须决定对其中哪一个参数进行缩减。其次,我们可能能够排除掉许多可能元素,但我们想选择其中最容易的一个。(例如最左边的端点,最小的数字)第三,我们可能想对问题加强限制条件(例如线段是有序排列的)。当然还有其他很多变化。例如我们可以假设我们已经知道对一些小于n的值的问题如何解决而不是仅仅的n-1。这往往是一个有效的假设。任何缩减问题规模的做法都是值得考虑的,因为这种做法能够引导我们回到问题的最基本情况,而这时往往我们能够直接解决。回到在归纳法中讨论的排序例子,我们可以把对n个元素的排序缩减为对两个各含n/2个元素的子集的排序。然后可以对这两个排好序的集合进行合并(引出一个称为归并排序的算法)。把问题分解(归纳性的)为一些相同的部分是一个很有用的技巧(我们将会在后面进行讨论),该技巧称为分治。

一些问题的缩减很容易就能实现,然而一些却很难实现。一些规模的缩减能够带来很不错的算法,然而一些却不行。在很多情况下这就是问题中唯一的困难之处,一旦做出了正确的选择那么剩下的就很容易了(例如在映射问题中元素i的选择那样)。这在数学中极其重要。没有人能够不通过首先思考如何选择一个归纳序列就直接跳到归纳证明中去。正如估计的那样,这在算法设计中也是很重要的。在这一部分我们将给出两个例子,在这两个例子中,缩减序列的重要性得到了体现。特别是名人的例子,它说明了一种不同于一般的顺序。

 

你可能感兴趣的:(USING INDUCTION TO DESIGN 使用归纳法设计算法 [5/14])