陣列分割——解題筆記
陣列分割——解題筆記
題目:有一個沒有排序、元素個數為2n的正整數陣列,要求:如何能把這個陣列分割為元素個數為n的兩個陣列,並使兩個子陣列的和最接近。
分析:這道題目可以用動態規劃求解,或者說是一個典型的0,1揹包問題,對於第i的數,到底是放進去還是不放,就要看放了對結果有什麼影響,不放對結果又有什麼影響。而結果是依據題目而言的,這道題目中的結果就是陣列之和。
注意,一般動態規劃陣列中,需要先初始化所有i的結果,初始化可以為1,或者0. 然後,從前往後,依次得到每個i的優化結果,而且需要注意的是,第i個的結果只和第i-1個的結果有關。
在這道題目中,我參考了參考中的一篇博文,感覺講的比較清楚,如下:
給出的虛擬碼為:
F[][][]← 0
for i ← 1 to 2*N
nLimit ← min(i,N)
do for j ← 1 to nLimit
do for k ← 1 to Sum/2
F[i][j][k] ← F[i-1][j][k]
if (k >= A[i] && F[i][j][k] < F[i-1][j-1][k-A[i]]+A[i])
then F[i][j][k] ← F[i-1][j-1][k-A[i]]+A[i]
return F[2N][N][Sum/2]
核心函式如下:
int splitArray(int a[], int len, int sum)
{
int*** X;
X = new int**[len+1];
for(int p = 0; p < len/2+1; p++)
{
X[p] = new int*[len/2+1];
for(int q= 0; q < sum+1; q++)
X[p][q] = new int[sum+1];
}
for(int i = 1; i <= len; i++)
{
int lim = min(i, len/2);
for(int j = 1; j <= lim; j++)
{
for(int k = 1; k <= sum; k++)
{
X[i][j][k] = X[i-1][j][k];
if(k >= a[i-1])
{
if(X[i][j][k] < X[i-1][j-1][k-a[i-1]] + a[i-1])
{
X[i][j][k] = X[i-1][j-1][k-a[i-1]] + a[i-1];
}
}
}
}
}
int result = X[len][len/2][sum];
//delete [][][]X; // 銷燬空間這種做法是錯誤的,應該和申請空間方法一樣
return result;
}
注意:其中申請三維動態空間的方法,以及銷燬的方法。
上面解法的空間複雜度為O(N^2Sum),而且用到的是三維空間,是可以進行優化的。
“
我們觀察前面不含路徑的虛擬碼可以看出,F[i][j][k]只與F[i-1][][]有關,這一點狀態方程上也能反映出來。所以我們可以用二維陣列來代替三維陣列來達到降低空間複雜度的目的。但是怎麼代替裡面存有玄機,我們因為F[i][j][k]只與F[i-1][][]有關,所以我們用二維陣列來代替的時候應該對F[i][j][k]的“j”維進行逆序遍歷。為什麼?因為只有這樣才能保證計算F[i][j][k]時利用的F[i-1][j][]和F[i-1][j-1][]是真正i-1這個狀態的值,如果正序遍歷,那麼當計算F[][j][]時,F[][j-1][]已經變化,那麼計算的結果就是錯誤的。
虛擬碼如下
[cpp] view plaincopy
F[][]← 0
for i ← 1 to 2*N
nLimit ← min(i,N)
do for j ← nLimit to 1
do for k ← A[i] to Sum/2
if (F[j][k] < F[j-1][k-A[i]]+A[i])
then F[j][k] ← F[j-1][k-A[i]]+A[i]
return F[N][Sum/2] and Path[][][]
”
動態規劃的題目寫起來還是不順額。。。
參考:
http://blog.csdn.net/wumuzi520/article/details/7028705
http://wenku.baidu.com/link?url=CQkQIsOqAYP41MuP9yavgklpHiST6BXXDi2zwfvGnRZEDHMF6S7LrwinwMPW3C6YAKkBw2i397aLNtppediKQ2nPJ4BSqFo8KUb0VbmA1Eu
相關文章
- [筆記] 解碼Nginx:陣列(Array)筆記Nginx陣列
- 陣列分割陣列
- GO 筆記-陣列Go筆記陣列
- JS 陣列筆記JS陣列筆記
- 陣列筆記1陣列筆記
- join 分割陣列陣列
- golang陣列分割Golang陣列
- IOS筆記之陣列iOS筆記陣列
- JavaScript筆記(6)陣列JavaScript筆記陣列
- 【筆記】字尾陣列筆記陣列
- NumPy 分割與搜尋陣列詳解陣列
- 六,陣列筆記及相關練習題大全陣列筆記
- C++ ——vector陣列筆記C++陣列筆記
- iOS筆記之陣列排序iOS筆記陣列排序
- JS陣列學習筆記JS陣列筆記
- 【筆記】oracle 陣列實現筆記Oracle陣列
- 三,列表和陣列(筆記)陣列筆記
- 【筆記/模板】樹狀陣列筆記陣列
- 【Java學習筆記之五】java陣列詳解Java筆記陣列
- Numpy陣列的組合與分割詳解陣列
- Java 學習筆記 二維陣列和物件陣列Java筆記陣列物件
- 陣列分割,把陣列分割成和相等的兩部分--遞迴方法陣列遞迴
- c++筆記_多維陣列C++筆記陣列
- 學習筆記——陣列方法整理筆記陣列
- Java學習筆記之陣列Java筆記陣列
- 學習筆記----樹狀陣列筆記陣列
- swift 學習筆記之陣列Swift筆記陣列
- 學習筆記----字尾陣列筆記陣列
- 字尾陣列 學習筆記陣列筆記
- 字尾陣列學習筆記陣列筆記
- 【刷題筆記】LeetCode-53 最大子陣列和筆記LeetCode陣列
- JavaScript 學習筆記 - 多維陣列變為一維陣列JavaScript筆記陣列
- JS常用陣列方法總結筆記JS陣列筆記
- 【C#學習筆記】陣列使用C#筆記陣列
- JavaScript split() 分割字串生成陣列JavaScript字串陣列
- LintCode 奇偶分割陣列陣列
- leetcode題解(陣列問題)LeetCode陣列
- 關於磁碟陣列,分割槽載入的問題(轉)陣列