最大子段和問題

2021-10-05 14:18:28 字數 3055 閱讀 3257

給定n個整數(可能為負整數)a1,a2,a3……an.求形如 ai,a(i+1),……,aj i,j=1,……n,i<=j

的子段和的最大值。當所有的整數均為負整數的時候定義其最大子段和為0,例如:當(a1,a2,a3,a4,a5,a6)=(-2,11,-4,13,-5,-2)時,最大子段和為 i=2,j=4(下標從1開始)。

列舉所有可能的起始下標(i=1,2,3,……,n)和終止下標(j=i,i+1……,j),累加i到j所有元素的和,並從中選取最大的子段和。

partsum()

i=j=1;

t=max_sum

(a,n,

&i,&j)

;print

("the most sum of section is"

,t);

print

("starting point is"

,i);

print

("end point is"

,j);

}max_sum

(int a,

int n,

int*best_i,

int*best_j)

if(this_sum>sum)}}

return sum;

}

如果將所給的序列a[1:n]分為長度相同的兩段a[1:n/2]和a[(n/2)+1:n],分別求出這兩段的最大子段和,則a[1:n]的最大子段和有三種情形。

(1)a[1:n]的最大欄位和與a[1:n/2]的最大欄位和相同

(2)a[1:n]的最大欄位和與a[(n/2)+1:n]的最大欄位和相同

(3)a[1:n]的最大子段和為a[i:j],且1<=i<=(n/2),(n/2)+1<=j<=n

(1)和(2)可遞迴求得,對於(3)而言,序列中的元素a[(n/2)]與a[(n/2)+1]一定在最大欄位中。因此,可以計算出a[i:(n/2)]的最大值s1;並計算出a[(n/2)+1:j]中的最大值s2.則s1+s2即為(3)的最優值。

partsum()

i=j=1;

t=max_sum

(a,n,

&i,&j)

;print

("the most sum of section is"

,t);

print

("starting point is"

,i);

print

("end point is"

,j);

}int

max_sum

(int a,

int n)

max_sub_sum

(int a,

int left,

int right)

else

}else

} s2=0;

rights=0;

for(i=center+

1;i<=right;i++)}

if(s1+s2if(s1+s2return s1+s2;

}}

用動態規劃法解決問題的思路很簡單,就是通過開闢儲存空間,儲存各個子問題的計算結果,從而避免重複的計算。其實就是用空間效率去換取時間效率。

記sum[i]為a[1]~a[i]的最大欄位和,記this_sum[i]為當前子段和。

this_sum[i]從i=1開始計算,當this_sum[i-1]>=0時,前面欄位的和對總和有貢獻,所以要累加當前元素的值;當this_sum[i-1]<0時,前面欄位的和對總和沒有貢獻,要重新開始累加,以後的子段和從i開始。sum[i]在記錄a[1]~a[i]的最大欄位和,不斷儲存新得到的較大的this_sum[i]。

初值:this_sum[0]=0; i=1,2……n時

this_sum[i]=this_sum[i-1]+a[i] ——> 當this_sum[i-1]>=0

this_sum[i]=a[i] ——> 當this_sum[i-1]<0

相應地sum[i]的遞推式如下:a[0]=0,i=1,2……n時,

sum[i]=sum[i-1] ——> 當this_sum[i]<=sum[i-1]

sum[i]=this_sum[i] ——> 當this_sum[i]>sum[i-1]

partsum()

i=j=1;

t=max_sum

(a,n,

&i,&j)

;print

("the most sum of section is"

,t);

print

("starting point is"

,i);

print

("end point is"

,j);

}max_sub_sum

(int a,

int n,

int*best_i,

int*best_j)

else

if(this_sum[j]

<0)

}return sum;

}

在上述演算法的空間上進行優化,儲存a[1]~a[j]的當前子段和的this_sum及當前最大子段和的sum都不必設定為n個元素的陣列,用普通變數就可以實現了。因為在遞推的過程中,只需儲存乙個值就足夠了。

partsum()

i=j=1;

t=max_sum

(a,n,

&i,&j)

;print

("the most sum of section is"

,t);

print

("starting point is"

,i);

print

("end point is"

,j);

}max_sub_sum

(int a,

int n,

int*best_i,

int*best_j)

else

if(this_sum<0)

}return sum;

}

最大子段和問題

給定n個整數 可能為負數 組成的序列a 1 a 2 a 3 a n 求該序列如a i a i 1 a j 的子段和的最大值。當所給的整均為負數時定義子段和為0 分治法 分析 首先將陣列分為兩部分,最大子段和 可以在陣列的左半部分也可以在右半部分,也可以橫跨分割點,因此我們只需要用分治思想求出左邊最大...

最大子段和問題

給定n 個整數 有可能是負數 組成的序列,要求分別用蠻力法,減治法和動態規劃法,求最該序列的最大子段和,並對它們的效率進行比較分析。也稱窮舉法或列舉法,是一種簡單直接地解決問題的方法,常常基於問題的描述,所以,蠻力法也是最容易應用的方法。它依賴的基本技術是遍歷,採用一定的策略依次處理待求解問題的所有...

最大子段和問題

問題描述 給定n個整數 可能為負數 組成的序列a 1 a 2 a 3 a n 求該序列如 a i a i 1 a j 當所給的整數均為負數時定義子段和為0.如果序列中全部是負數則 最大子段和為0,依次所定義 所求的最優值max,1 i問題解析 動態規劃演算法 dp i 包含元素i的子段和 dp 0 ...