1. 程式人生 > 實用技巧 >Ubuntu 20.04 開機執行自定義指令碼

Ubuntu 20.04 開機執行自定義指令碼

題目:

最大子列和問題

問題描述:

給定K個整陣列成的序列{N​1​​,N​2​​, ...,NK​​},“連續子列”被定義為{Ni​​,Ni+1​​, ...,Nj​​},其中1≤ijK“最大子列和”則被定義為所有連續子列元素的和中最大者。例如給定序列{ -2, 11, -4, 13, -5, -2 },其連續子列{ 11, -4, 13 }有最大的和20。現要求你編寫程式,計算給定整數序列的最大子列和。

本題旨在測試各種不同的演算法在各種資料情況下的表現。各組測試資料特點如下:

  • 資料1:與樣例等價,測試基本正確性;
  • 資料2:102個隨機整數;
  • 資料3:103個隨機整數;
  • 資料4:104個隨機整數;
  • 資料5:105個隨機整數;

輸入格式:

輸入第1行給出正整數K(≤100000);第2行給出K個整數,其間以空格分隔。

輸出格式:

在一行中輸出最大子列和。如果序列中所有整數皆為負數,則輸出0。

輸入樣例:

6

-2 11 -4 13 -5 -2

輸出樣例:

20

演算法描述:

本題採用分治法的思想,將原問題一分為二,分別求取左子列和右子列的最大子列和,另外,還有一種比較特殊的情況,就是可能所求的子列橫跨中間元素,這種情況要單獨拿出來討論。

最後比較三者的值,返回其最大值。

演算法時間及空間複雜度分析:

 1 #include <iostream>
 2  using namespace
std; 3 4 void input(int a[],int num) 5 { 6 for(int i=0;i<num;i++) 7 cin >> a[i]; 8 } 9 10 int compare(int lmax,int rmax,int mmax) 11 { 12 int max=0; 13 if(lmax>=rmax && lmax>=mmax) max=lmax; 14 else if(rmax>=lmax && rmax>=mmax) max=rmax;
15 else max=mmax; 16 return max; 17 } 18 19 int maxsum(int a[], int left, int right) 20 { 21 //if(left>right) return 0; 22 if(left==right) 23 { 24 if(a[left]>0) return a[left]; 25 else return 0; 26 } 27 int mid=(left+right)/2; 28 int lmax=maxsum(a,left,mid); 29 int rmax=maxsum(a,mid+1,right); 30 int lmmax=0; 31 int lsum=0; 32 for(int i=mid;i>=left;i--) 33 { 34 lsum+=a[i]; 35 if(lsum>lmmax) lmmax=lsum; 36 } 37 int rmmax=0; 38 int rsum=0; 39 for(int i=mid+1;i<=right;i++) 40 { 41 rsum+=a[i]; 42 if(rsum>rmmax) rmmax=rsum; 43 } 44 45 int mmax=lmmax+rmmax; 46 return compare(lmax,rmax,mmax); 47 } 48 49 int main() 50 { 51 int num; 52 cin >> num; 53 int *a=new int[num+1]; 54 input(a,num); 55 cout << maxsum(a,0,num-1); 56 delete []a; 57 return 0; 58 }

時間複雜度:該演算法的時間分為分治求左右子列和與跨越中間元素的子列的和。其中,分治的問題規模為原問題的一半,則時間複雜度為2Tn/2,後者從中間元素出發,分別掃描左右兩邊的數,故時間複雜度為On.根據主定理Tn=2Tn/2+On=On log n)。

空間複雜度:該演算法只用到了輔助變數,故空間複雜度為O1)。

心得體會:

我覺得分治法的難點在於找到問題規模最小到能求解的情況,並且在寫遞迴函式的時候很容易繞暈。通過本題的練習,更加清晰地理解了分治法的思想。另外,與同伴的結對程式設計小籠包有所提高。