給定長度為n的陣列a,從中選擇k個長度為m的子陣列,要求和最大。
形式描述為:選擇
k 個子陣列[l1
, r1
], [l2
, r2
], ..., [lk
l1, rk
](1 ≤ l1
≤r1 ≤l
2 ≤ r
2
≤... ≤lk
≤ rk
≤ n; ri
−ri+
1
), 使得∑k
i=1∑
rij=
lipj
【思路1】先從簡單粗暴的方法入手,怎麼辦?尋找所有的k個長度為m的子陣列,然後選擇其中和最小的。第乙個長度為m的子陣列開始位置可能為0...(k-1)*m,然後第二個子陣列的下標?第三個子陣列下標?太複雜了而且時間複雜度肯定超高,不能忍,換個方法吧。
【思路2】再看一下問題,要求和最大,求最值問題十有**都是dp問題,試試吧。dp題目子問題怎麼定義是關鍵,然後這東西基本只能靠經驗了(嗯,演算法導論上就是這麼說的)。從後往前考慮,那麼對於最後乙個元素,只有兩種情況,被選中到子陣列中或者沒有被選到子陣列中。如果被選中,那麼首先計算最後m個元素的和,剩下的問題就化為從前面長度為n-m的陣列中選擇k-1組和最大的子陣列。如果沒選中最後乙個,也好辦,直接轉化為從前面n-1個元素中選擇k組和最大的子陣列。分析後我們有:
子問題定義: dp[i][j] = 從前i個元素中選擇j個子陣列的最大和
狀態轉移方程: dp[i][j] = max(dp[i-1][j], dp[i-m][j-1] + sum(a[i-m]...a[i-1]))
初始條件: dp[0][j] = 0; dp[i][0] = 0; if (i < j * m) dp[i][j] = 0;
1 #include 2 #include3 #include 4 #include 5 #include 6 #include 7
using
namespace
std;89
intmain()
1019
20//
dp[i][j] = choose j pairs integers from the first i elements
21//
then base on the ith is chosen or not, there are two case:
22//
not choose ith element, the dp[i][j] = dp[i-1][j]
23//
choose ith element, the dp[i][j] = dp[i-m][j-1] + sum(a[i-1]...a[i-m])
24//
so dp[i][j] = max(dp[i-1][j], dp[i-m][j-1] + sum(a[i-1]...a[i-m])
25//
base case: assert (i >= j * m) if not 0 dp[i][j] = 0
26//
the problem is equal to find dp[n][k]
2728 vectorlong
long> > dp(n+1, vector
long>(k+1, 0
));29
30//
base case
31for (int i = 0; i < n + 1; ++i)
3239}40
}4142//
bottom to up
43for (int i = 1; i < n + 1; ++i)
445253}
54}5556
long
long ans =dp[n][k];
57 cout << ans <
58return0;
59 }
書上講解 最大m段子段和問題
描述 題解 設f i j 表示前i個數字分成了j段的最大子段和。則f i j max f i 1 j a i 第i個數字和第j段合在一起 f k j 1 a i 第i個數字作為第j段的第乙個數字,同時在j 1段的情況中找到和最大的那個 這樣的時間複雜度是 o m n 2 的,的寫法在 1中 接下來我...
陣列的第k個最大元素
提交 總結在未排序的陣列中找到第 k 個最大的元素。請注意,你需要找的是陣列排序後的第 k 個最大的元素,而不是第 k 個不同的元素。示例 1 輸入 3,2,1,5,6,4 和 k 2 輸出 5 示例 2 輸入 3,2,3,1,2,4,5,5,6 和 k 4 輸出 4 說明 你可以假設 k 總是有效...
陣列中的第k個最大元素
在未排序的陣列中找到第 k 個最大的元素。請注意,你需要找的是陣列排序後的第 k 個最大的元素,而不是第 k 個不同的元素。示例 1 輸入 3,2,1,5,6,4 和 k 2 輸出 5 示例 2 輸入 3,2,3,1,2,4,5,5,6 和 k 4 輸出 4 說明 你可以假設 k 總是有效的,且 1...