中北大学算法分析与设计实验报告七(动态规划问题)

中北大学算法分析与设计实验报告七(动态规划问题)

1.实验名称

实验七 动态规划问题实验

2.实验目的

综合应用实验2:最大子段和问题
利用蛮力算法、分治算法和动态规划算法解决问题,分析不同算法的时间复杂度,并能够针对算法进行优化。

3.训练知识点集群

(1)根据实验内容设计算法伪代码进行算法描述;
(2)利用C++/C/Java等编程语言对算法伪代码进行工程化实现;
(3)输入测试用例对算法进行验证;
(4)列出算法时间复杂度模型并与计算机运行统计时间进行对比分析。

4.实验内容

给定n个整数(可能为负数)组成的序列a[1],a[2],…,a[n],求该序列如a[i]+a[i+1]+…+a[j]的字段和的子段和的最大值。当所给的整数均为负数时,定义子段和为0。
例如:当(a[1],a[2],a[3],a[4],a[5],a[6])=(-2,11,-4,13,-5,-2)时,最大子段和为20。

5.实验原理

只有当前一位加和为正数时才对字段和有益处,而当前一位加和为负数时,其对当前位并无益处,因此直接置零,从当前位开始从新计算子段和,并不断维护最大子段和。
分治法
算法描述如下
针对最大子段和这个具体问题本身的结构。如果将所给的序列a[1:n]分为长度相等的两段a[1:n/2]和a[n/2+1:n],分别求出这两段的最大子段和,则a[1:n]的最大子段和有三种情况:
(1)a[1:n]的最大子段和与a[1:n/2]的最大子段和相同
(2)a[1:n]的最大子段和与a[n/2+1:n]的最大子段和相同
(3)a[1:n]的最大子段和为a[i]+…+a[j],并且1<=i<=n/2,n/2+1<=j<=n。
对于(1)和(2)两种情况可递归求得,但是对于情况(3),容易看出a[n/2],a[n/2+1]在最大子段中。因此,我们可以在a[1:n/2]中计算出s1=max(a[n/2]+a[n/2-1]+…+a[i]),0<=i<=n/2,并在a[n/2+1:n]中计算出s2= max(a[n/2+1]+a[n/2+2]+…+a[i]),n/2+1<=i<=n。则s1+s2为出现情况(3)的最大子段和。
递推法
若记b[j]=max(a[i]+a[i+1]+…+a[j]),其中1<=i<=j,并且i<=j<=n。则所求的最大子段和为max b[j],1<=j<=n。
由b[j]的定义可易知,当b[j-1]>0时b[j]=b[j-1]+a[j],否则b[j]=a[j]。故b[j]的递推方程为:
b[j]=max(b[j-1]+a[j],a[j]),1<=j<=n。

6.源代码实现

#include
#define MAX 1002
int main(){
    int n,a[MAX];
    scanf("%d",&n);
    for(int i=0;i<n;i++)
        scanf("%d",&a[i]);
//--------D[i]表示的是以a[i]为终止位置的最优解-------
    int D[n],max=a[0];//max=a[0]很关键,它和第18行选出最大的有关系,要不然的话,第18行只是从a[1]~a[n-1]选出最大的
    D[0]=a[0];//第一个数字前面没有数字 所以以a[0]为终止位置的最优解就是它自己
    for(int i=1;i<n;i++){//每一个数字都找到以它为终止位置的最优解
        if(D[i-1]>0)/*如果a[i]前面的那个数字的最优解大于0,那么再加上a[i]得D[i],则D[i]就是以a[i]结
        尾的所有可能中的最优解*/
            D[i]=a[i]+D[i-1];
        else
            D[i]=a[i];/*如果a[i]前面的那个数字的最优解小于0,那么以a[i]结尾的所有可能中的最优解就是它本身*/
        if(D[i]>max)
            max=D[i];//选出最大的
    }
    for(int i=0;i<n;i++)//输出结果
        printf("%d ",D[i]);
    printf("\nmax is %d\n",max);
//--------D[i]表示的是以a[i]为起始位置的最优解------
    D[n-1]=a[n-1];
    max=a[0];
    for(int i=n-2;i>=0;i--){
        if(D[i+1]>0)
            D[i]=a[i]+D[i+1];
        else
            D[i]=a[i];
        if(D[i]>max)
            max=D[i];
    }
    for(int i=0;i<n;i++)
        printf("%d ",D[i]);
    printf("\nmax is %d\n",max);
//不需要数组,用一个变量temp保存a[i]前面的以a[i-1]为终止最优解,这是第一种方法的简洁版
    int temp=0;
    max=a[0];
    for(int i=0;i<n;i++){
        if(temp>0)
            temp+=a[i];
        else
            temp=a[i];
        if(temp>max)
            max=temp;
    }
    printf("max is %d\n",max);
    return 0;
}

7.实验结论及心得体会

通过本次实验,明白了动态规划的实质就是把大问题拆成许多个小问题,通过寻找大问题和小问题之间的递推关系,解决每个小问题,最终达到解决原问题的结果。动态规划可以描述成通过填写表把所有已经解决的子问题答案记录下来,在新问题里需要用到的子问题可以直接提取,避免了重复计算,从而节约了时间,所以在问题满足最优性原理之后,用动态规划解决问题的核心就在于填表,表填写完毕,最优解也就找到。

你可能感兴趣的:(算法,动态规划,c语言)