給定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 ...