【发布时间】:2018-07-28 05:57:05
【问题描述】:
免责声明:
所描述的问题看起来像是竞赛中的一项任务。我没有参加其中的任何一个,我不知道任何正在进行的比赛,这可能涉及到这个问题。如果有任何问题,我会关闭问题以保持公平!
我有一个问题: 给定一个包含值和整数 K 的数组 A,将 A 拆分为恰好 K 个不重叠的连续子数组,使得具有最小和的子数组与子数组最大和之间的差异最小。允许将 A 向任意方向旋转任意数字。
考虑一个例子:
输入:A = [5 1 1 1 3 2],K = 3
输出:[5][1 1 1][3 2],最大和 = 5,最小和 = 3,结果 = 2
我有部分工作的代码(非常丑陋,我的错,但这并不意味着生产质量):
#include <climits>
#include <cstdio>
#include <cstring>
const int max_n = 50;
const int max_k = 20;
int deps[max_n];
int max (int x, int y) {
return x > y ? x : y;
}
int min (int x, int y) {
return x < y ? x : y;
}
int sum (int a[], int start, int end) {
int res = 0;
for (int i = start; i <= end; ++i) res += a[i];
return res;
}
int k_partitioning(int k, int n, int deps[]) {
int res = INT_MAX;
// consider all possible rotations/shifts
for(int offset = 0; offset < n; ++offset) {
for(int l_min = 0; l_min < n; ++l_min) {
for(int r_min = l_min; r_min < n; ++r_min) {
// check minimal sum subarray
int min_sum = sum (deps, l_min, r_min);
int dp[k][n];
for (int s = 0; s < k; ++s) {
for (int q = 0; q < n; ++q) {
dp[s][q] = 0;
}
}
// assuming that current sum is a target sum
dp[0][r_min-l_min] = min_sum;
for(int p = 1; p < k; ++p) {
for(int l_max = 0; l_max < n; ++l_max) {
for(int r_max = 0; r_max < n; ++r_max) {
int max_sum = sum(deps, l_max, r_max);
if (max_sum >= min_sum) dp[p][r_max] = max(dp[p-1][l_max], max_sum);
} // l_maxs
} // r_maxs
} // partitions
// printing dp
// skip incorrect partitioning, when not all K partitions were used
if (dp[k-1][n-1] == 0) continue;
// update difference
res = min (res, dp[k-1][n-1] - min_sum);
} // end min sum seg
} // start min sum seg
//break;
} // cuts
return res;
}
int main(int argc, char* argv[]) {
int k = 0;
scanf("%d", &k);
int n = 0;
scanf("%d", &n);
for (int i = 0; i < n; ++i) {
scanf("%d", &deps[i]);
}
printf ("%d\n", k_partitioning(k, n, deps));
return 0;
}
这个想法很简单:假设当前分区具有最小和,枚举所有可能的最大分区,设置动态编程以生成具有最小值的最大和,检查差异。总复杂度:O(K*N^4)。
我的问题是它未能通过一些测试,我一直在解决它。有人可以帮我吗?
测试失败,例如:
N = 4,K = 2,A = [6 13 10 2]
更新
这个版本应该修复一些以前的问题。首先,它消除了“偏移”上的浪费循环,并在 l_min 循环的末尾添加了一个数组旋转。其次,我注意到 dp 不能用 0 初始化——这是最小化任务,所以应该用一些大的值初始化(取决于问题的常量,这里的 max_value 已经超出了值域)。最后,间隔不应再重叠 - 每个总和不包括间隔的左端。但是,它仍然没有产生预期的结果。
#include <climits>
#include <cstdio>
#include <cstring>
const int max_value = 200000;
const int max_n = 50;
const int max_k = 20;
int deps[max_n];
int max (int x, int y) {
return x > y ? x : y;
}
int min (int x, int y) {
return x < y ? x : y;
}
int sum (int a[], int start, int end) {
int res = 0;
for (int i = start; i <= end; ++i) res += a[i];
return res;
}
int k_partitioning(int k, int n, int deps[]) {
int res = max_value;
for(int l_min = 0; l_min < n; ++l_min) {
for(int r_min = l_min; r_min < n; ++r_min) {
int min_sum = sum (deps, l_min+1, r_min);
int dp[k][n];
for (int s = 0; s < k; ++s) {
for (int q = 0; q < n; ++q) {
dp[s][q] = max_value;
}
}
// assuming that current sum is a target sum
dp[0][r_min-l_min] = min_sum;
for(int p = 1; p < k; ++p) {
for(int l_max = 0; l_max < n; ++l_max) {
for(int r_max = l_max; r_max < n; ++r_max) {
int max_sum = sum(deps, l_max+1, r_max);
if (max_sum >= min_sum) dp[p][r_max] = max(dp[p-1][l_max], max_sum);
} // l_maxs
} // r_maxs
} // partitions
// skip incorrect partitioning, when not all K partitions were used
if (dp[k-1][n-1] == max_value) continue;
// update difference
res = min (res, dp[k-1][n-1] - min_sum);
} // end min sum seg
// rotate an array to consider different starting points
int tmp[n];
for (int i = 0; i < n; ++i) {
int new_idx = i + n + 1;
tmp[new_idx % n] = deps[i];
}
for(int i = 0; i < n; ++i) deps[i] = tmp[i];
} // start min sum seg
return res;
}
int main(int argc, char* argv[]) {
int k = 0;
scanf("%d", &k);
int n = 0;
scanf("%d", &n);
for (int i = 0; i < n; ++i) {
scanf("%d", &deps[i]);
}
printf ("%d\n", k_partitioning(k, n, deps));
return 0;
}
【问题讨论】:
-
这个想法是合理的,但代码有一些问题。在我的脑海中,你并没有真正使用外循环(偏移),所以你肯定没有得到正确的旋转。 sum 函数在两端都包含在内,因此您实际上是在查看在其端点重叠的子数组。您的复杂性估计是错误的:我计算了 5 个嵌套循环,其中一个上升到 n,一个上升到 k。加上 sum 函数循环,使其总体上更接近 O(KN^6)。否则,它看起来与正确相差不远(达到 O(KN^4) 可能需要一些工作)。
-
@gus 谢谢!我已经解决了一些问题,请查看更新后的帖子。但是,它仍然没有给出预期的结果。
标签: c algorithm dynamic-programming mathematical-optimization