算法(一) -- 动态规划

动态规划:解决分解的子问题不独立的情况。用动态规划法解决问题的思路很简单,就是通过开辟存储空间,存储子问题的计算结果,从而避免重复计算。动态规划其实有很强的阶段递推思想,用前一阶段存储的计算结果,递推后一阶段的结果,是一种全面继承前期信息的方法。
动态规划=贪婪策略+递推(降价)+存储递推结果。
贪婪策略、递推算法都是在“线性”地解决问题,而动态规划则是全面分阶段地解决问题。可以通俗地说,动态规划是“带决策的多阶段、多方位的递推算法”。我们用一道题来更深入的理解一下动态规划。
问题描述:
给定n个整数(可能会负整数)a1,a2,….an。求形如的子段和的最大值。当所有整数均为负整数时定义其最大子段和为0。
例如,当(a1,a2,a3,a4,a5,a6)=(-2,11,-4,13,-5,-2)时,最大子段和为
Σak=20(k=I,从j开始) i=2,j=4(下标从1开始)
一、问题分析:
我的想法是运用动态规划来找出最大子段和,并记录起始位置及结束位置。
首先分析一下最大子段和的子结构,令b[j]表示从a[0]~a[j]的最大子段和。
b[j]的当前值只有两种情况:
(1) a[0]~a[j]都为正数,则最大子段一直连续到a[j]
(2) 以a[j]为起点的子段 //如果不是第(1)种,则(1)肯定为负,舍去,此处用start变量保存新起点
还有一种情况,那就是最大字段没有包含a[j],如果没有包含a[j]的话,那么在算b[j]之前的时候我们已经算出来了,注意我们只是算到位置为j的地方,所以最大子段在a[j]后面的情况我们可以暂时不考虑。
由此我们得出b[j]的状态转移方程为:b[j]=max{b[j-1]+a[j], a[j]},
所求的最大子段和为max{b[j],0<=j<n}
。进一步我们可以将b[]数组用一个变量代替。
二、算法时间复杂度:
算法中只用了一层循环,时间复杂度为O(n),是解决该问题效率最高的算法。

AC代码:

#include <stdio.h>
int main()
{
    int a[10005],i,n;
    while(scanf("%d",&n)!=EOF)//整数总个数
    {
   		for(i=0;i<n;i++)         
	   		scanf("%d",&a[i]);
   			int b=0,sum=a[0],start=0,end=0;//sum为最长子段和,初始值赋值为a[0],b为当前子段和 
        	for(i=0;i<n;i++)
        	{
             	if(b>0)
				 	b+=a[i];
            	else
				 {
				 	b=a[i];
	               //如果前面小于等于零,前面子段的和对总和没有贡献,重新累加,因为如果相加,会影响后面结果,所以抛弃前面总和
				 	start=i;
	             //从位置i重新开始 
			     }
             	if(b>sum)
			 	{
                 	 sum=b;  
				  	 end=i;
			 	}
        	}
 
 		printf("%d\n%d  %d\n",sum,start+1,end+1);//输出最长子段和、子段开始位置、子段结束位置
   }
   return 0;
}

运行结果:
在这里插入图片描述

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值