hdu1003:(dp解决查找最大的连续的子序列和)

题目链接:http://acm.hdu.edu.cn/showproblem.php?pid=1003

题目描述:
就是给你一个数组,需要你找出最大的连续子序列的和,和起始位置
如:(6,-1,5,4,-7),这样一个数组,最大的连续子序列就是6+(-1)+5+4=14,起始点为:1,结束点为:4,故输出14,1,4
然后我这里再说几个特殊的例子:
0 6 0
输出的是6 1 2
6 -1 1
输出的是6 1 1
6 -7 -8 14
输出的是14 4 4

解题思路

这道题需要用到动态规划。我们定义dp[100005]数组,第n个的dp即dp[n]就是代表着前n个的子序列的最大值。
状态转移方程:dp[1] = a[1];
dp[i] = max(dp[i-1]+dp[i],dp[i])【n>=2时执行】

如果dp[n-1]是小于0的,那么就代表着前面的n-1个的和是负数,那么可以抛弃掉前面n-1个,用temp来记录新的起点位置。
如果dp[n]>max就将dp[n]赋值个max,即max = dp[n]【保证max始终是最大值】同时也要更新起始和结束点。

比如:6 -1 5 4 -7
首先,先将里面的所有的数都存入dp数组里面
然后,再初始化dp[1]=6,start=1,end=1,max=dp[1]=6的值
然后从2循环到5
dp[2] = 6+(-1) = 5 小于max不做操作
dp[3] = 5+5 = 10大于max,更新max,start和end的值
dp[4] = 10 + 4大于max,更新max,start和end的值
dp[5] = 10 +(-7)小于max不做操作

【注】当dp[n-1]<0的时候需要用temp,而不是直接用start来接收。
这是为了避免出现:6 -6 -2 -3 -4这种情况,如果j从第3个循环就开始小于0了,
并且一直到5结束为止,如果直接在里面写成start = j 的话会导致start = 5是错误答案
而当dp[n]>max才执行更新,保证了这个start的值的正确性

ac代码:

#include
#include

#define N 100005

int main(){
     
	int dp[N];
	int max;
	int start,end;
	int T;
	int n;
	int temp;
	scanf("%d",&T);
	
	for(int i = 1;i <= T;i++){
     
		memset(dp,0,sizeof(dp));
		scanf("%d",&n);
		for(int k = 1;k <= n;k++){
     
			scanf("%d",&dp[k]);
		}
		start = 1;
		end = 1;
		max = dp[1];
		temp = 1;//记录起点,当这第j个数的dp[j]>max时才更新到start上去,
				
		for(int j = 2;j <= n;j++){
     
				if(dp[j-1] >= 0){
     //证明前面一个是正数,或者是前面的部分加起来是正数 
					dp[j] = dp[j] + dp[j-1];
				}else{
     //前面加起来是负数,就不能作为起点,得选这个作为新的起点 
					temp = j;//这是为了避免出现:6 -6 -2 -3 -4这种情况,如果j从第3个循环就开始小于0了,
				//并且一直到5结束为止,如果直接在里面写成start = j 的话会导致start = 5是错误答案 
				}
				
				if(dp[j] > max){
     //证明当前的数大于最大值 
					max = dp[j];
					end = j;
					start = temp;
				}
		}
		
		if(i>=2){
     
			printf("\n");
		}
		printf("Case %d:\n",i);
		printf("%d %d %d\n",max,start,end);
		
		
		
	}
	
	
	
	return 0;
	
} 

你可能感兴趣的:(hdu1003:(dp解决查找最大的连续的子序列和))