动态规划程序设计(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(n2)

【例】拦截导弹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.

【参考程序】(逆推法)

时间: 2024-08-05 08:50:57

动态规划程序设计(5)的相关文章

转载:动态规划

来源:http://blog.sina.com.cn/s/blog_7727572f01011461.html 动态规划(dynamic programming)是运筹学的一个分支,是求解决策过程(decision process)最优化的数学方法.20世纪50年代初美国数学家R.E.Bellman等人在研究多阶段决策过程(multistep decision process)的优化问题时,提出了著名的最优化原理(principle of optimality),把多阶段过程转化为一系列单阶段问

算法导论——lec 11 动态规划及应用

和分治法一样,动态规划也是通过组合子问题的解而解决整个问题的.分治法是指将问题划分为一个一个独立的子问题,递归地求解各个子问题然后合并子问题的解而得到原问题的解.与此不同,动态规划适用于子问题不是相互独立的情况,即各个子问题包含公共的子子问题.在这种情况下,如果用分治法会多做许多不必要的工作,重复求解相同的子子问题.而动态规划将每个子问题的解求解的结果放在一张表中,避免了重复求解. 一. 动态规划介绍 1. 动态规划方法介绍: 动态规划主要应用于最优化问题, 而这些问题通常有很多可行解,而我们希

代码与算法集锦-归并排序+树状数组+快排+深度优先搜索+01背包(动态规划)

归并排序 求逆序数 归并排序是建立在归并操作上的一种有效的排序算法.该算法是采用分治法(Divide and Conquer)的一个非常典型的应用. 首先考虑下如何将将二个有序数列合并.这个非常简单,只要从比较二个数列的第一个数,谁小就先取谁,取了后就在对应数列中删除这个数.然后再进行比较,如果有数列为空,那直接将另一个数列的数据依次取出即可. //将有序数组a[]和b[]合并到c[]中 void MemeryArray(int a[], int n, int b[], int m, int c

简单动态规划

初次接触到ACM,发现有很多的问题都不会 认识到了难度,自己还是蒟蒻(巨弱)啊 这次学到的是一道区域型的动态规划问题吧,虽然对很多人来说很简单 一开都没啥思路就会画个图 后面看了题解才知道要用到动态规划,可是还是不会啊 然后去了解了下,啥叫动态规划问题 动态规划程序设计是对解最优化问题的一种途径.一种方法,而不是一种特殊算法.不像搜索或数值计算那样,具有一个标准的数学表达式和明确清晰的解题方法. 动态规划程序设计往往是针对一种最优化问题,由于各种问题的性质不同,确定最优解的条件也互不相同,因而动

DP(动态规划)学习心得

动态规划学习心得 说实话吧,动态规划(DP)确实是一个比较难的知识点,对于初学者来说,是一个难过的坎(笔者的脸呢?开玩笑.).动态规划就是我从初学开始遇到的最神奇的解法,它不同于暴力搜索,也不同于一般的贪心,能够以出乎人意料的时间复杂度(近似于O(n^2))解决一些难题,算法远远优于一般的深搜(O(2^n)).不过,动态规划的思维性比较强,必须会设好状态,正确写出状态转移方程,并且能够准确判断有无最优子结构. 其实有点像贪心,但是它有局部最优解推导向整体最优解的过程,形象一点说,动态规划的“眼光

ACM总结报告!

ACM总结报告 算法设计 姓名:郭嘉 学号:2015590 专业:网络工程二班 指导老师:费玉奎. 第一次听说ACM这个事情是我们的计算机导论老师岳训老师介绍给我的,他可以算是我计算机的启蒙老师,带我走进了计算机这个大世界.他让我知道了一个优秀的程序员就像是一位"武林高手"一样,需要掌握 "内功"和"外功",外功指的就是程序设计语言,比如C.C++.Java.Python.而内功就是指算法,数据结构,设计模式等等.这"内功"和

leetcode-Maximum Subarray

https://leetcode.com/problems/maximum-subarray/ Find the contiguous subarray within an array (containing at least one number) which has the largest sum. For example, given the array [−2,1,−3,4,−1,2,1,−5,4],the contiguous subarray [4,−1,2,1] has the l

算法(一)概述

概述: 算法(Algorithm)是指解题方案的准确而完整的描述,是一系列解决问题的清晰指令,算法代表着用系统的方法描述解决问题的策略机制.也就是说,能够对一定规范的输入,在有限时间内获得所要求的输出.如果一个算法有缺陷,或不适合于某个问题,执行这个算法将不会解决这个问题.不同的算法可能用不同的时间.空间或效率来完成同样的任务.一个算法的优劣可以用空间复杂度与时间复杂度来衡量.算法中的指令描述的是一个计算,当其运行时能从一个初始状态和(可能为空的)初始输入开始,经过一系列有限而清晰定义的状态,最

《挑战程序设计竞赛》课后练习题解集——3.4 熟练掌握动态规划

<挑战程序设计竞赛>课后练习题解集——3.4 熟练掌握动态规划 状态压缩DP POJ 2441  有N头牛,M个槽,N,M≤20,每头牛只在指定的pi个槽里进食,不与其他牛共享槽.问有多少种分配方案. dp[i][S],当前第i头牛要进食,槽的使用状态为S 1 #include <cstdio> 2 #include <cstring> 3 #include <vector> 4 using namespace std; 5 6 int n, m; 7 in