zoukankan      html  css  js  c++  java
  • 动态规划程序设计(5)

    【例】求最长不下降序列

    【问题描述】:

    设有由n个不相同的整数组成的数列,记为:b(1)、b(2)、……、b(n)且b(i)<>b(j)  (i<>j),若存在i1<i2<i3< … < ie 且有b(i1)<b(i2)< … <b(ie)则称为长度为e的不下降序列。程序要求,当原数列给出之后,求出最长的不下降序列。

    例如13,7,9,16,38,24,37,18,44,19,21,22,63,15。例中13,16,18,19,21,22,63就是一个长度为7的不下降序列,同时也有7 ,9,16,18,19,21,22,63长度为8的不下降序列。

    【算法分析】:根据动态规划的原理,由后往前进行搜索。

    1)、对b(n)来说,由于它是最后一个数,所以当从b(n)开始查找时,只存在长度为1的不下降序列;

    2)、若从b(n-1)开始查找,则存在下面的两种可能性:

    ①若b(n-1)<b(n)则存在长度为2的不下降序列b(n-1),b(n)。

    ②若b(n-1)>b(n)则存在长度为1的不下降序列b(n-1)或b(n)。

    3)、一般若从b(i)开始,此时最长不下降序列应该按下列方法求出:

    在b(i+1),b(i+2),…,b(n)中,找出一个比b(i)大的且最长的不下降序列,作为它的后继。

    【数据结构】:

    为算法上的需要,定义一个数组整数类型二维数组b(N,3)

    1)、b(i,1)表示第i个数的数值本身;

    2)、b(i,2)表示从i位置到达N的最长不下降序列长度

    3)、b(i,3)表示从i位置开始最长不下降序列的下一个位置,若b[i,3]=0则表示后面没有连接项。

    【求解过程】:

    ①    从倒数第二项开始计算,后面仅有1项,比较一次,因63>15,不符合要求,长度仍为1

    ②    从倒数第三项开始其后有2项,需做两次比较,得到目前最长的不下降序列为2,如下表:

     

    11

    12

    13

    14

    ……

     

    11

    12

    13

    14

     

     

    22

    63

    15

    ……

     

    21

    22

    63

    15

     

     

    2

    1

    1

    ……

     

    3

    2

    1

    1

     

     

    13

    0

    0

    ……

     

    12

    13

    0

    0

    【一般处理过程】:

    ①在i+1,i+2,…,n项中,找出比b[I,1]大的最长长度L以及位置K;

    ②若L>0,则b[I,2]:=L+1;b[I,3]:=k;

    最后本题经过计算,其数据存储表如下:

    1

    2

    3

    4

    5

    6

    7

    8

    9

    10

    11

    12

    13

    14

    13

    7

    9

    16

    38

    24

    37

    18

    44

    19

    21

    22

    63

    15

    7

    8

    7

    6

    3

    4

    3

    5

    2

    4

    3

    2

    1

    1

    4

    3

    4

    8

    9

    7

    9

    10

    13

    11

    12

    13

    0

    0

     1 初始化:
     2 for i:=1 to n do
     3 begin
     4   read(b[i,1]);
     5   b[i,2]:=1;b[i,3]:=0;
     6 end;
     7 下面给出求最长不下降序列的算法:
     8 for i:=n-1 downto 1 do
     9 begin
    10  L:=0;k:=0;
    11  for j:=i+1 to n do
    12   if(b[j,1]>b[i,1])and(b[j,2]>L) then begin
    13 L:=b[j,2];
    14 k:=j;
    15                                       end;
    16  if L>0 then begin
    17 b[i,2]:=L+1;
    18 b[i,3]:=k;
    19              end;
    20 end;
    21 下面找出最长不下降序列:
    22 k:=1;
    23 for j:=1 to n do
    24  if b[j,2]>b[k,2] then k:=j;
    25 最长不下降序列长度为B(k, 2)序列
    26 while k<>0  do
    27 begin
    28  write(b[k,1]:4);
    29  k:=b[k,3];
    30 end;
     1 var 
     2 n,i,L,k,j:integer;
     3   b:array[1..100,1..3]of integer;
     4 begin
     5  readln(n);
     6  for i:=1 to n do
     7  begin
     8   read(b[i,1]);
     9   b[i,2]:=1;b[i,3]:=0;
    10  end;
    11 for i:=n-1 downto 1 do
    12   begin
    13    L:=0;k:=0;
    14    for j:=i+1 to n do
    15     if(b[j,1]>b[i,1])and(b[j,2]>L) then begin
    16 L:=b[j,2]; k:=j;
    17                                          end;
    18   if L>0 then begin
    19                b[i,2]:=L+1;b[i,3]:=k;
    20               end;
    21  end;
    22  k:=1;
    23  for j:=1 to n do
    24   if b[j,2]>b[k,2] then k:=j;
    25  writeln('max=',b[k,2]);
    26  while k<>0  do
    27   begin
    28     write(b[k,1]:4);
    29     k:=b[k,3];
    30   end;
    31  writeln;
    32 end.
    参考程序

    程序运行结果:

    输入:14

    13 7 9 16 38 24 37 18 44 19 21 22 63 15

    输出:max=8

    7  9  16  18  19  21  22  63

     1 var
     2   i,n,max,st,en:longint;
     3   b:array[1..100000,1..3] of longint;
     4 procedure Init;
     5 var i:longint;
     6 begin
     7   readln(n);
     8   for i:=1 to n do
     9    begin
    10      read(b[i,1]);
    11      b[i,2]:=1; b[i,3]:=0;
    12    end;
    13 end;
    14 procedure Lis;
    15 var i,j,maxl,loca:longint;
    16 begin
    17   for i:=n-1 downto 1 do
    18    begin
    19      maxl:=0; loca:=0;
    20      for j:=i+1 to n do
    21       if b[i,1]<b[j,1] then
    22         //begin
    23           if b[j,2]>maxl then
    24            begin
    25              maxl:=b[j,2];
    26              loca:=j;
    27            end;
    28         //end;
    29      if maxl>0 then
    30       begin
    31         b[i,2]:=maxl+1;
    32         b[i,3]:=loca;
    33       end;
    34    end;
    35 end;
    36 procedure Findmax;
    37 var i:longint;
    38 begin
    39   max:=0;
    40   for i:=1 to n do
    41    if b[i,2]>max then
    42     begin
    43       max:=b[i,2];
    44       st:=i;
    45     end;
    46 end;
    47 procedure Outit;
    48 var i:longint;
    49 begin
    50   writeln(max);
    51   i:=st;
    52   while i<>0 do
    53    begin
    54      write(b[i,1],' ');
    55      i:=b[i,3];
    56    end;
    57 end;
    58 begin
    59   Init;
    60   Lis;
    61   Findmax;
    62   Outit;
    63 end.
    我的板子 O(n²)

    【例】拦截导弹1

    某国为了防御敌国的导弹袭击,发展出一种导弹拦截系统。但是这种拦截系统有一个缺陷:虽然它的第一发炮弹能够到达任意的高度,但是以后每一发炮弹都不能高于前一发的高度。某天,雷达捕捉到敌国的导弹来袭,由于该系统还在试用阶段。所以只有一套系统,因此有可能不能拦截所有的导弹。输入导弹依次飞来的高度(雷达给出的高度不大于30000的正整数)。计算这套系统最多能拦截多少导弹。

    输入:N颗依次飞来的导弹高度,(导弹个数<=1000)。

    输出:一套系统最多拦截的导弹数,并依次打印输出被拦截导弹的高度。

    在本题中不仅要求输出最优解,而且还要求输出最优解的形成过程。为此,我们设置了一张记忆表C[i],在按从后往前方式求解的过程中,将每一个子问题的最佳决策保存起来,避免在输出方案时重复计算。

    阶段i:     由右而左计算导弹n‥导弹1中可拦截的最多导弹数(1≤i≤n);

    状态B[i]:  由于每个阶段中仅一个状态,因此可通过一重循环

    for i := n-1 downto 1 do  枚举每个阶段的状态B[i];

    决策k:在拦截导弹i之后应拦截哪一枚导弹可使得B[i]最大(i+1≤k≤n),

    1   2   3   4   5   6   7   8   9   10  11  12  13  14  I

    13  7   9   16  38  24  37  18  44  19  21  22  63  15  A[I]    {高度}

    2   1   1   2   4   3   3   2   3   2   2   2   2   1   B[I]    {可拦截数}

    2   0   0   14  6   8   8   14  10  14  14  14  14  0   C[I]    {再拦截}

     1 var
     2   a,b,c:array[1..1000] of longint;
     3   n,i,j,k,max:longint;
     4 begin
     5  n:=0;                                                           {初始化,读入数据}
     6  while not eoln do 
     7 begin                                                               {eoln :行结束}
     8 inc(n);read(a[n]); 
     9 b[n]:=1; c[n]:=0;
    10   end;
    11  readln;
    12  for i:=n-1 downto 1 do                         {枚举每一个阶段的状态,设导弹i被拦截}
    13 begin                  
    14    max:=0; j:=0;
    15    for k:=i+1 to n do                      {枚举决策,计算最佳方案中拦截的下一枚导弹}
    16     if (a[k]<=a[i]) and (b[k]>max) then begin  max:=b[k];j:=k; end;
    17     b[i]:=max+1; c[i]:=j;                 {若导弹i之后拦截导弹j为最佳方案,则记下}
    18   end;
    19   max := 0;
    20   for i := 1 to n do                                 {枚举求出一套系统能拦截的最多导数}
    21     if b[i]>max then begin max:=b[i]; j:=i; end;
    22   writeln('Max = ',b[j]);                                               {打印输出结果}
    23   while j>0 do 
    24 begin
    25    write(a[j]:5); j:=c[j];
    26     end;
    27  end.
    【参考程序】(逆推法)
  • 相关阅读:
    vue--vuex详解
    vue2.0的一个小demo,
    vue---子调父 $emit (把子组件的数据传给父组件)
    高阶函数总结
    三个方法(apply、call、bind)
    JS的一些总结(函数声明和函数表达式的区别,函数中的this指向的问题,函数不同的调用方式,函数也是对象,数组中的函数调用)
    原型对象(下)
    案例:贪吃蛇
    原型对象(上)
    案例(拖拽对话框、高清放大镜、自制滚动条、元素的隐藏方式、表格隔行变色、tab切换效果、字符串拼接、刷新评论)
  • 原文地址:https://www.cnblogs.com/vacation/p/6052621.html
Copyright © 2011-2022 走看看