Algorithm 优化:将数组分成长度不大于k的连续子序列,使每个子序列的最大值之和最小
优化Algorithm 优化:将数组分成长度不大于k的连续子序列,使每个子序列的最大值之和最小,algorithm,dynamic-programming,Algorithm,Dynamic Programming,优化O(n^2)算法到O(n log n) 问题陈述 给定由n正整数组成的数组A。将数组划分为长度不大于k的连续子序列,使每个子序列的最大值之和最小。这里有一个例子 如果n=8和k=5并且数组的元素是1 4 1 3 4 7 2,则最佳解决方案是1 | 4 1 3 4 7 | 2 2。总和将是max{1}+max{4,1,3,4,7}+max{2,2}=1+7+2=10 O(n^2)溶液 设dp[i]为子问题数组A[0]的问题陈述中的最小和。。。A[i]dp[0]=A[0],对于0最大值) max
O(n^2)
算法到O(n log n)
问题陈述
给定由n
正整数组成的数组A
。将数组划分为长度不大于k
的连续子序列,使每个子序列的最大值之和最小。这里有一个例子
如果n=8
和k=5
并且数组的元素是1 4 1 3 4 7 2
,则最佳解决方案是1 | 4 1 3 4 7 | 2 2
。总和将是max{1}+max{4,1,3,4,7}+max{2,2}=1+7+2=10
O(n^2)溶液
设dp[i]
为子问题数组A[0]的问题陈述中的最小和。。。A[i]
dp[0]=A[0]
,对于0
(dp[-1]=0
)
//A,n,k,-已定义
//dp-全部初始化为INF
dp[0]=A[0];
用于(自动i=1;i=0&&j>=i-k+1;j--){
如果(A[j]>最大值)
max=A[j];
自动求和=最大值+(j>0?dp[j-1]:0);
如果(总和
O(n日志n)?
问题作者声称在
O(nlogn)
时间内解决这个问题是可能的,并且有一些人能够通过测试用例。如何对其进行优化?注意:我将稍微更改您的动态规划关系,以便在j=0
时没有特殊情况。现在dp[j]
是第一个j
术语A[0]、…、A[j-1]
的答案:
dp[i]=min(dp[j]+max(A[j],…,A[i-1]),i-k=dp[i]
,在下面的转换中,您不需要dp[j]
,因为max(A[j],…,A[l])=max(A[i],…,A[l])
(因此在i
处切割总是比在j
处切割更好
<> >让<代码> C[j]=max(A[j+1],…,[L])/COD>(其中<代码> L>代码>是我们当前的动态编程步骤中的索引,即,C++程序中的<代码> I/C> >
然后,您可以在内存中保存一些索引集x1<…
(动态规划关系转换的“有趣”索引),这样:dp[x1]<…
(1)。然后自动C[x1]>=…>=C[xm]
(2)
要存储{x1,…,xm}
,我们需要一些支持以下操作的数据结构:
- 向后弹出(当我们从
移动到i
时,我们必须说i+1
现在无法访问)或向前弹出(参见插入)i-k
- 向前推
(当我们计算了x
,我们通过删除相应的元素,在保留(1)的同时插入它)dp[i]
- 计算
min(dp[xj]+C[xj],1您当前的算法具有O(n*k)复杂度,因为第二个循环回溯的步数不超过
步。在找到使dp[i]最小的j之后,如果该j导致最后一段的元素数严格小于k,那么该j也将为dp[i+1]提供有效的解决方案.设m是dp[i]最优解的最后一段中的最大元素。A[i+1]可以是>m,或者想知道这个问题在现实世界中的一个示例应用,知道吗?你的代码似乎在我问题中给出的示例上返回了14。我不确定我是否理解你的正确操作,但我是这样做的:。此外,我在索引1处开始k
,A
和dp
,并且C
在这段代码中。我不确定如何处理属性(2),因此我希望对此进行一些澄清。(C[j]=max{A[j],…,A[i]}
仅此测试消除就让我的解决方案通过了测试用例,但出于好奇。谢谢!)@AquaBlitz11:我更新了我的答案。现在它应该可以工作了(请注意,您不需要>=dp[i]
,因为这里的所有元素都是不同的)。multiset
// A, n, k, - defined // dp - all initialized to INF dp[0] = A[0]; for (auto i = 1; i < n; i++) { auto max = -INF; for (auto j = i; j >= 0 && j >= i-k+1; j--) { if (A[j] > max) max = A[j]; auto sum = max + (j > 0 ? dp[j-1] : 0); if (sum < dp[i]) dp[i] = sum; } } // answer: dp[n-1]
template<class T> void relaxmax(T& r, T v) { r = max(r, v); } vector<int> dp(n + 1); vector<int> C(n + 1, -INF); vector<int> q(n + 1); vector<int> ne(n + 1, -INF); int qback = 0, qfront = 0; auto cmp = [&](const int& x, const int& y) { int vx = dp[x] + C[x], vy = dp[y] + C[y]; return vx != vy ? vx < vy : x < y; }; set<int, decltype(cmp)> s(cmp); dp[0] = 0; s.insert(0); q[qfront++] = 0; for (int i = 1; i <= n; ++i) { C[i] = A[i - 1]; auto it_last = lower_bound(q.begin() + qback, q.begin() + qfront, i, [=](const int& x, const int& y) { return C[x] > C[y]; }); for (auto it = it_last; it != q.begin() + qfront; ++it) { s.erase(*it); C[*it] = A[i - 1]; ne[*it] = i; if (it == it_last) s.insert(*it); } dp[i] = dp[*s.begin()] + C[*s.begin()]; while (qback < qfront && dp[q[qfront]] >= dp[i]) { s.erase(q[qfront]); qfront--; } q[qfront++] = i; C[i] = -INF; s.insert(i); if (q[qback] == i - k) { s.erase(i - k); if (qback + 1 != qfront && ne[q[qback]] > q[qback + 1]) { s.erase(q[qback + 1]); relaxmax(C[q[qback + 1]], C[i - k]); s.insert(q[qback + 1]); } qback++; } } // answer: dp[n]