博客
关于我
强烈建议你试试无所不能的chatGPT,快点击我
【算法30】从数组中选择k组长度为m的子数组,要求其和最小
阅读量:5278 次
发布时间:2019-06-14

本文共 2212 字,大约阅读时间需要 7 分钟。

原题链接:

问题描述:

给定长度为n的数组a[],从中选择k个长度为m的子数组,要求和最大。

形式描述为:选择$k$个子数组[$l_1$, $r_1$], [$l_2$, $r_2$], ..., [$l_k$l1, $r_k$] (1 ≤ $l_1$ ≤$r_1$ ≤$l_2$ ≤ $r_2$ ≤... ≤$l_k$ ≤ $r_k$ ≤ n; $r_i-r_i+1$), 使得$\sum_{i=1}^{k}\sum_{j=l_i}^{r_i}p_j$

问题分析:

【思路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;

AC代码如下:

1 #include 
2 #include
3 #include
4 #include
5 #include
6 #include
7 using namespace std; 8 9 int main()10 {11 int n, m, k;12 cin >> n >> m >> k;13 14 vector
v(n, 0);15 for (int i = 0; i < n; ++i)16 {17 cin >> v[i];18 }19 20 // dp[i][j] = choose j pairs integers from the first i elements21 // 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] = 026 // the problem is equal to find dp[n][k]27 28 vector
> dp(n+1, vector
(k+1, 0));29 30 // base case31 for (int i = 0; i < n + 1; ++i)32 {33 for (int j = 0; j < k + 1; ++j)34 {35 if (i < j * m)36 {37 dp[i][j] = 0;38 }39 }40 }41 42 // bottom to up43 for (int i = 1; i < n + 1; ++i)44 {45 for (int j = 1; j < k + 1; ++j)46 {47 if (i >= j * m)48 {49 long long lastPairSum = accumulate(v.begin() + i - m, v.begin() + i, 0LL);50 dp[i][j] = max(dp[i-1][j], dp[i-m][j-1] + lastPairSum); 51 }52 53 }54 }55 56 long long ans = dp[n][k];57 cout << ans << endl;58 return 0;59 }

注意点:

这道题目很简单的,为什么要记录下来呢,因为我用了int,出现了overflow,想了半天也没想明白到底错在哪里了,脑子真是瓦特啦,记下来以免重蹈覆辙。

转载于:https://www.cnblogs.com/python27/p/3984061.html

你可能感兴趣的文章
[@Controller]3 详解@CookieValue,@PathVariable,@RequestBody,@RequestHeader,@RequestParam
查看>>
DataTable的一些特殊用法:Select
查看>>
MVC中Excel数据的导入与导出
查看>>
fk makefile文件的一些问题
查看>>
我们都是被中科院“诓骗”来的学生
查看>>
Storm中Spout使用注意事项小结
查看>>
Could not load file or assembly 'System.Web.Http
查看>>
'workspace' in VS Code
查看>>
System Databases in SQL Server
查看>>
Python函数
查看>>
SqlServer的两种插入方式效率对比
查看>>
linux下使用boost python (直接用g++生成动态库,不使用bjam)
查看>>
iOS tableView中section的headerView的位置
查看>>
[Leetcode 104]求二叉树的深度Depth of BinaryTree
查看>>
Python 方法指南
查看>>
Fibonacci数
查看>>
在线颜色配置器
查看>>
开发者必备,超实用的PHP代码片段!
查看>>
perl debug 2
查看>>
四则运算1
查看>>