Description
给定有n个整数(可能为负整数)组成的序列a1,a2,...,an,求该序列连续的子段和的最大值。 如果该子段的所有元素和是负整数时定义其最大子段和为0。
Input
第一行有一个正整数n(n<1000),后面跟n个整数,绝对值都小于10000。直到文件结束。
Output
输出它的最大子段和。
Sample Input
6 -2 11 -4 13 -5 -2
Sample Output
20
1.暴力跑表法(时间复杂度(n³))(AC oj:912 ms)
跑每一个点,用一个二维数组的坐标 i , j表示i -----> j 字段内的和。分别求出后,跑这个二维数组,取出最大值。
1 #include <iostream> 2 #include<string.h> 3 using namespace std; 4 5 int main() 6 { 7 int n1; 8 int i,j,k,max1,m,n; 9 int sum=0; 10 cin>>n1; 11 int ap[n1]; 12 int a[n1][n1]; 13 14 for(i=0;i<n1;i++) 15 cin>>ap[i]; 16 memset(a,0,sizeof(a)); //数组清零 17 a[0][0]=ap[0]; 18 for(i=0;i<n1;i++) 19 a[i][i]=ap[i]; 20 for(i=0;i<n1;i++) 21 for(j=i;j<n1;j++) 22 { 23 if(i!=j) 24 { 25 if(j!=0) 26 { 27 k=j-1; 28 a[i][j]=a[i][k]+ap[j]; 29 } 30 } 31 } 32 33 max1=a[0][0]; 34 for(i=0;i<n1;i++) 35 for(j=0;j<n1;j++) 36 { 37 if(max1<a[i][j]) 38 { 39 max1=a[i][j]; 40 m=i; 41 n=j; 42 } 43 } 44 cout<<max1; 45 return 0; 46 }
2.暴力记忆法(时间复杂度(n²))(AC oj:12 ms)
此方法同第一种方法,是暴力法的升级版。
二维数组也充当记忆数组,记忆当前点之前字段的和。此是只需要加上当前点即可。
1 #include <iostream> 2 #include<string.h> 3 using namespace std; 4 5 int main() 6 { 7 int n1; 8 int i,j,k,max1,m,n; 9 int sum=0; 10 cin>>n1; 11 int ap[n1]; 12 int a[n1][n1]; 13 for(i=0;i<n1;i++) 14 cin>>ap[i]; 15 memset(a,0,sizeof(a)); 16 a[0][0]=ap[0]; 17 for(i=0;i<n1;i++) 18 a[i][i]=ap[i]; 19 for(i=0;i<n1;i++) 20 for(j=i;j<n1;j++) 21 { 22 if(i!=j) 23 { 24 if(j!=0) 25 { //关键点! 26 k=j-1; //不用从i到j,只需要求出上一个点i到j-1即可,再加上j点 27 a[i][j]=a[i][k]+ap[j]; 28 } 29 } 30 } 31 32 max1=a[0][0]; 33 for(i=0;i<n1;i++) 34 for(j=0;j<n1;j++) 35 { 36 if(max1<a[i][j]) 37 { 38 max1=a[i][j]; 39 m=i; 40 n=j; 41 } 42 } 43 cout<<max1; 44 return 0; 45 }
3.分治法(时间复杂度(n·logn)) (AC oj:0 ms)
分治法:①分解:将原问题分解成若干规模较小与原问题形式一致且相互独立的子问题
②求解:对子问题分别求解
③合并:将子问题的解合并成原问题的解
1 #include <iostream> 2 #include<string.h> 3 using namespace std; 4 int sum(int a[],int left,int right); 5 int main() 6 { 7 8 int n; 9 cin>>n; 10 int i; 11 int a[n]; 12 for(i=0;i<n;i++) 13 cin>>a[i]; 14 int max1=sum(a,0,n-1); 15 cout<<max1; 16 return 0; 17 } 18 int sum(int a[],int left,int right) 19 { 20 int sum1=0; 21 int mid=(left+right)/2; 22 if(left==right) 23 { 24 if(a[left]>0) 25 sum1=a[left]; 26 else 27 sum1=0; 28 } 29 else 30 { 31 int leftsum=sum(a,left,mid); 32 int rightsum=sum(a,mid+1,right); 33 34 int s1=0; 35 int lefts=0; 36 int i; 37 for(i=mid;i>=left;i--) 38 { 39 lefts=lefts+a[i]; 40 if(lefts>s1) 41 s1=lefts; 42 } 43 44 int s2=0; 45 int rights=0; 46 for(i=mid+1;i<=right;i++) 47 { 48 rights=rights+a[i]; 49 if(rights>s2) 50 s2=rights; 51 } 52 sum1=s1+s2; 53 if(sum1<leftsum) 54 sum1=leftsum; 55 if(sum1<rightsum) 56 sum1=rightsum; 57 } 58 return sum1; 59 }
4.动态规划(时间复杂度(n))(AC oj:0 ms)
#include <iostream> using namespace std; int main() { int n; int i,j; cin>>n; int a[n]; int b[n]; for(i=0;i<=n;i++) cin>>a[i]; b[0]=a[0]; for(i=1;i<n;i++) { b[i]=a[i]+b[i-1]; if(a[i]>b[i]) b[i]=a[i]; } int max=b[0]; for(i=1;i<=n;i++) if(b[i]>max) max=b[i]; cout<<max; }