luogu1115:最大子段和:贪心/二分+递归

题目连接

  • 该题是luogu试炼场的2-13:T2

题目大意

  1. n个数字,求子段中,最大的连续和;

题目分析


解题思路1:贪心

  1. 设当前是 i ,则前面的“段”的和不能是负数;
  2. 所以只要前面的“段”的和不是负数, i 就可能加进去;
  3. 如果前面的“段”的和 是负数, i 就重新开一段。

贪心的代码:

比较短,理解是关键

//luogu1115:最大子段和 

//贪心 
 
#include<bits/stdc++.h>
using namespace std;
 
int n,x,s=0,ans;
  
int main()
{
	scanf("%d",&n);
	
	scanf("%d",&x);//第一个数字单独存储 
	s=x; 
	ans=x;
	if(s<0) s=0;	
	
	for(int i=2;i<=n;i++)
	{
		scanf("%d",&x);
		
		s+=x;//前缀和 
		if(ans<s) ans=s;//记录答案 
		
		if(s<0) s=0;//如果前面的段是负数,就不要了 		
	}
	
	printf("%d",ans);

	return 0;
}



思路2:线段树式的递归

  • 设符合要求的段是 [x,y] ;
  • 这一段可能出现在:
  1. L <= x < y <= mid ;
  2. mid < x < y <= R ;
  3. L <= x < mid < y <= R ;
  • 所以不断二分下去,回溯的时候求解。
  • 注意:[x,y] 是连续的,所以一定要从mid向两边求和!

代码2:类似线段树的二分递归

  • 把回溯的内容理解透,才是真正理解递归
//luogu1115:最大子段和 

//利用类似线段树的思想 
//用递归的来做 
 
#include<bits/stdc++.h>
using namespace std;
 
const int mx=2e5+5,mi=-2e5+5;
int a[mx],n;

int dfs(int l,int r)
{
	if(l==r) return a[l]; //最下层的位置
	
	int mid=(l+r)/2,s1=mi,s2=mi;
	
	int s=0;
	for(int i=mid;i>=l;i--)//从中间向左:求出左边的最大连续和 
	{
		s+=a[i];
		s1=max(s1,s);
	}
	
	s=0;
	for(int i=mid+1;i<=r;i++)//从中间向右:求出右边的最大连续和
	{
		s+=a[i];
		s2=max(s2,s);
	}
	
	return max(max(dfs(l,mid),dfs(mid+1,r)),s1+s2);
}

int main()
{
	scanf("%d",&n);
	
	for(int i=1;i<=n;i++) 
	{
		scanf("%d",&a[i]);
	}
	
	int ans=dfs(1,n);
	
	printf("%d",ans);

	return 0;
}


猜你喜欢

转载自blog.csdn.net/liusu201601/article/details/89922088