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; }