算法第三章上机实践报告

1.1问题描述

给定n个整数(可能为负数)组成a[1],a[2],a[3],…,a[n],求该序列如a[i]+a[i+1]+…+a[j]的子段和的最大值。当所给的整数均为负数时,定义子段和为0。要求算法的时间复杂度为O(n)。

1.2算法描述

#include <bits/stdc++.h>

#define max 10010

using namespace std;

int MaxSum(int n,int *a){

       int D[max];

       int sum=0;

       D[n]=a[n];//以序列结尾为开头的最大子段和必等于该序列结尾的数值

       for(int i=n-1;i>=1;i--){

              if(D[i+1]<0){

                     D[i]=a[i]; //D[i]表示以a[i]为开头的最大子段和

              }

              else{

                     D[i]=D[i+1]+a[i];// D[i+1]>=0时必须加上a[i]才是D[i]的最优值

              }

              if(sum<D[i]){

                     sum=D[i];//记录最优解,即所求的序列最大子段和

              }

       }

       return sum;

}

 

int main(){

       int n;

       int a[max];

       cin>>n;

       for(int i=1;i<=n;i++){

              cin>>a[i];

       }

       cout<<MaxSum(n,a);

}

 

1.3问题求解

1.3.1 递归方程

D[i]={D[i+1]+a[i],a[i]}

D[i]表示以a[i]为开头的最大子段和

1.3.2 填表

以本次实验的输入样例为例,给定序列为-2 11 -4 13 -5 -2共6个数,首先将6个数填入a数组中:

a1

a2

a3

a4

a5

a6

-2

11

-4

13

-5

-2

随后填表D,填表顺序是从后往前填:

根据D[i]的含义,D6一定是填-2

D1

D2

D3

D4

D5

D6

 

 

 

 

 

-2

随后填D5,由于D6小于0,加上只会让D5更小,所以D5等于a5

D1

D2

D3

D4

D5

D6

 

 

 

 

-5

-2

再填D4,道理同上,没必要加上D5,所以D4等于a4

D1

D2

D3

D4

D5

D6

 

 

 

13

-5

-2

接下来往前填D3,这时D4是大于0的,所以D3=D4+a3

D1

D2

D3

D4

D5

D6

 

 

9

13

-5

-2

依此类推,最后得到的一维表

D1

D2

D3

D4

D5

D6

18

20

9

13

-5

-2

所以根据表可知,该序列的最大子段和为20

1.3.3算法时间复杂度及空间复杂度

时间复杂度:O(n)

空间复杂度:用到了一维数组,空间复杂度O(n)

1.4 心得体会

  一开始不理解D[i]表示的是什么意思,简单地以为D[1]就是最后要求的结果,导致输出的结果出错,经过老师讲解后发现其实D[i]的含义很好理解。通过这次实践,又学到了一个求最大子数组(最大子段和)的更优算法,比起前边分治法求最大子数组,动态规划算法的时间效率又大大提高了。

2.对动态规划算法的理解体会

动态规划算法通常用于求解具有某种最优性质的问题。动态规划算法与分治法类似,其基本思想也是将待求解问题分解成若干个子问题,先求解子问题,然后从这些子问题的解得到原问题的解。与分治法不同的是,适合于用动态规划求解的问题,经分解得到子问题往往不是互相独立的。若用分治法来解这类问题,则分解得到的子问题数目太多,有些子问题被重复计算了很多次。我们可以用一个表来记录所有已解的子问题的答案。不管该子问题以后是否被用到,只要它被计算过,就将其结果填入表中。在需要时再找出已求得的答案,这样就可以避免大量的重复计算,节省时间。

 

posted @ 2021-10-26 20:27  白蔡  阅读(40)  评论(0编辑  收藏  举报