编程之美读书笔记2.15 - 子数组之和的最大值(二维)
http://blog.csdn.net/pipisorry/article/details/39083073
问题:
求二维数组(矩阵)的子矩阵之和的最大值。
亦可见:http://poj.org/problem?id=1050
解法1:(解释见注释)
每个子矩阵由列长、行长和左上角的元素位置决定。如果我们指定左上角的元素位置 (i,j) 和列长 c,那么可以求所有这些子矩阵中和最大的。然后,变化列长 c,可以求以 (i,j) 为左上角的最大和子矩阵。最所有左上角位置再求最大和子矩阵,问题就解决了。令 OPT(i,j,c) 表示以 (i,j) 为左上角,列长为 c 的最大和子矩阵之和,OPT(i,j) 表示以 (i,j) 为左上角的最优解,而 S(i,u,v) 表示第 i 行中从列 u 到列 v所有元素之和。则
OPT(i,j,c) = OPT(i+1,j,c) + S(i,j,j+c-1)
OPT(i,j) = max { OPT(i,j,c) : 1 <= c <= n }
其中,j+c-1 <= n。当 i >m 时, OPT(i,j,c) = 0。一共有 O(mn) 个 OPT(i,j) 子问题,而每个 OPT(i,j) 又可以有 n 个决策,因此,总的解规模有 O(mn2 ) 个 OPT(i,j,c)。每个这样的子问题可以在 O(1) 时间内解决(想想怎么做到),因此,时间复杂度为 O(mn2 )。
/* 直接枚举法O( N^2*M^2*O(sum()) ) Time Limit Exceeded */
static int submatrixSum(int **a, int row, int row_end, int col, int col_end){int sum = 0;for(int i = row; i <= row_end; i++)for(int j = col; j <= col_end; j++)sum += a[i][j];return sum;
}
static int maxSubmatrixSum1(int **a, int n){int max_sum = INT_MIN;int sum;int max_row, max_row_end, max_col, max_col_end;for(int row = 0; row < n; row++){for(int col = 0; col < n; col++){ //子矩阵左上角位置for(int row_end = row; row_end < n; row_end++)for(int col_end = col; col_end < n; col_end++){ //4个属性确定一个子矩阵sum = submatrixSum(a, row, row_end, col, col_end); //计算每个子矩阵的和if(sum > max_sum){max_sum = sum;/*max_row = row;max_row_end = row_end;max_col = col;max_col_end = col_end;*///printf("%d\n", max_sum);}}}}/*printf("\n col\tcol_end\n %d\t%d\n", max_col, max_col_end); //输出子矩阵位置(4个属性)printf("row %d\nrow_end %d\n", max_row, max_row_end);*/return max_sum;
}
解法2:
/* DP算法 O(N^2*M) */
static int maxSubmatrixSum2(int **a, int n){int ***row_sum = (int ***)malloc(sizeof(int **) * n);for(int i = 0; i < n; i++)assert( row_sum[i] = (int **)malloc(sizeof(int *) * n) );for(int i = 0; i < n; i++)for(int j = 0; j < n; j++)assert( row_sum[i][j] = (int *)malloc(sizeof(int) * n) );//计算row_sum[i][j][c]为第i行j列到c列的和for(int i = 0; i < n; i++) //初始化row_sum[i][j][c]为0for(int j = 0; j < n; j++)memset(row_sum[i][j], 0, sizeof(int) * n); //!!!for(int i = n - 1; i >= 0; i--){for(int j = 0; j < n; j++){for(int c = j; c < n; c++)if(c == 0)row_sum[i][j][c] = a[i][c];elserow_sum[i][j][c] = row_sum[i][j][c - 1] + a[i][c];}}//将row_sum[i][j][c]转换成第i行j列到c列的和的最优解for(int i = n - 2; i >= 0; i--){ //row_sum[n-1][j][c]不变for(int j = 0; j < n; j++)for(int c = j; c < n; c++){if(row_sum[i+1][j][c] > 0)row_sum[i][j][c] += row_sum[i+1][j][c];}}//求以[i, j]为左上角的矩形最优解int **optij = (int **)malloc(sizeof(int *) * n);for(int i = 0; i < n; i++)optij[i] = (int *)malloc(sizeof(int) * n);for(int i = 0; i < n; i++)memset(optij[i], INT_MIN, sizeof(int) * n);for(int i = 0; i < n; i++){for(int j = 0; j < n; j++)for(int c = j; c < n; c++){if(row_sum[i][j][c] > optij[j][j])optij[j][j] = row_sum[i][j][c];}}//求整体最优解int max_sum = INT_MIN;for(int i = 0; i < n; i++){for(int j = 0; j < n; j++){if(optij[i][j] > max_sum)max_sum = optij[i][j];}}return max_sum;
}
解法3:
/* 最优算法 AC 63MS */
static int maxSubmatrixSum(int **a, int n){//初始化col_sum, col_sum[i][j][k]为第i和j行之间第k列元素的和int *** col_sum;assert( col_sum = (int ***)malloc(sizeof(int **) * n) );for(int i = 0; i < n; i++)assert( col_sum[i] = (int **)malloc(sizeof(int *) * n) );for(int i = 0; i < n; i++){for(int j = 0; j < n; j++){assert( col_sum[i][j] = (int *)malloc(sizeof(int) * n) );memset(col_sum[i][j], 0, sizeof(int) * n);}}//计算第0和j(>=1)行之间第k列的和for(int k = 0; k < n; k++){ col_sum[0][0][k] = a[0][k]; //初始化col_sum[0][0][k]为首行数据for(int j = 1; j < n; j++)col_sum[0][j][k] = col_sum[0][j - 1][k] + a[j][k]; //!!!}//计算第i和j行之间第k列的和for(int k = 0; k < n; k++){for(int i = 1; i < n; i++)for(int j = i; j < n; j++)col_sum[i][j][k] = col_sum[i - 1][j][k] - a[i - 1][k];}//计算最大子矩阵和int max_mat_sum = INT_MIN;for(int i = 0; i < n; i++){for(int j = i; j < n; j++){int row_sum = 0; //第i和j行之间最大行array和(压缩矩阵)for(int k = 0; k < n; k++){row_sum += col_sum[i][j][k];if(row_sum < 0)row_sum = 0;if(row_sum > max_mat_sum)max_mat_sum = row_sum;}}}return max_mat_sum;
}
测试:
int main(){assert( freopen("BOP\\maxSubmatrixSum.in", "r", stdin) );//int cases; //测试案例数目//scanf("%d", &cases);//while(cases--){int n; //每个案例中matrix维度scanf("%d", &n);int **a = (int **)malloc(sizeof(int*) * n);for(int i = 0; i < n; i++)a[i] = (int *)malloc(sizeof(int) * n);for(int i = 0; i < n; i++)for(int j = 0; j < n; j++)scanf("%d", &a[i][j]);//printf("%d\n", maxSubmatrixSum1(a, n) );//printf("%d\n", maxSubmatrixSum2(a, n) );printf("%d\n", maxSubmatrixSum(a, n) );//}fclose(stdin);return 0;
}
测试案例:
3
2
1 1
1 1
4
0 -2 -7 0
9 2 -6 2
-4 1 -4 1
-1 8 0 -2
3
3 -1 4
3 -1 4
3 -1 4
output:
4
15
18
from:
http://blog.csdn.net/pipisorry/article/details/39083073
ref:
Maximum Submatrix & Largest Rectangle
编程之美 书p190
编程之美读书笔记2.15 - 子数组之和的最大值(二维)相关推荐
- 编程之美-2.14-求数组的子数组之和的最大值
这个以前写过,见求数组的最长子数组之和的最大值 这里说一下后面扩展题目. 1. 简述 1) 如果数组首尾相连,即允许找到一组数字(A[i],···,A[n-1], A[0],···, A[j]),请使 ...
- 《编程之美》2.14求子数组之和的最大值
解法三: 考虑数组的第一个元素A[0],以及最大的一段数组(A[i]...A[j])跟A[0]的关系,有一下三种情况: 1.0=i=j 元素A[0]本身构成和最大一段: 2.0=i< ...
- 编程之美 2.14求数组的子数组之和的最大值
对于一个有N个元素的数组,a[0]~a[n-1],求子数组最大值. 如:数组A[] = [−2, 1, −3, 4, −1, 2, 1, −5, 4],则连续的子序列[4,−1,2,1]有最大的和6. ...
- 《团队开发一(求一个数组的连续的子数组之和的最大值)》
<团队开发一(求一个数组的连续的子数组之和的最大值)> (1)设计思想:一般的,求一个数组的最大子数组之和即是按数组顺序依次让前几个数的和与下一个数进行比较,设一变量来装每次比较后的较大的 ...
- 求数组的子数组之和的最大值
一个有N个整数元素的一维数组( A[0], A[1], ... , A[n-2], A[n-1]),子数组之和的最大值是什么?(要求子数组的元素是连续的) 例子:有数组( -2, 5, 3, -6, ...
- 【C】课堂结对联系-求整数数组的子数组之和的最大值(党云龙、黄为)
测试题目 求整数数组的子数组之和的最大值. 题目分析 首先是明确题目的目的:求最大值:其次是考虑子数组求和.这里将求最大值写成一个单独的函数.主函数未测试函数.这里用到了二重循环,时间复杂度为N^2. ...
- 算法-求数组的子数组之和的最大值
一个一维int数组,这个数组有很多子数组,那么子数组之和的最大值是什么呢? 思考 1.题目说的子数组是连续的: 2.题目只需要求和,并不需要返回子数组的具体位置: 3.数组的元素是整数,所以数组可能包 ...
- 编程之美2.14 求数组的子数组之和的最大值
这是一个在面试中出现概率很高的一道题目,就拿我来说吧,面试了5家公司中,两家公司问了这道题目,可见,这道题目是非常经典的. 解题思想也不是很难,我熟悉的有:两种解题办法: ...
- 求数组的子数组之和的最大值IV
在之前的基础上又安排了二维数组的,在课上一开始是理解错要求了,简单的以为用循环数组就能解决,但是却忽视了子数组是否能构成矩形,之后课下和同学们讨论,主要是多重遍历,但是我还是没搞明白怎么构成新的二维数 ...
- Programe_Of_Beauty:2.14 求数组的子数组之和的最大值
问题:一个有N个整数元素的一维数组,那么求子数组和的最大值. 分析:首先我们明确问题,子数组是联系的,不用返回元素的位置,元素是整数,可能为正,负或0.我们来看看最经典的解法:a[0],a[1]-a[ ...
最新文章
- 机器学习-线性回归LinearRegression
- python爬虫之cookie方式自动登录巴比特网
- SAP上线前数据重置方式总结
- CodeChef - NWAYS 组合数 朱世杰恒等式
- [蓝桥杯2017初赛]包子凑数-模拟+巧妙枚举
- 03_linux 常用命令(上)
- nginx 上传 文件超时设置_Ingressnginx自定义配置文件
- java equals() output_Java中的==和equals
- 工程伦理2021秋期末考答案|网课期末考答案|学堂在线|清华大学李正风教授
- Windows 10系统下载----生成iso镜像文件
- 四阶行列式如何降阶_四阶行列式的计算方法
- 计算机网络会议和期刊
- 使用C语言自定义函数计算三角形周长
- HDU 2883 kebab(离散化+最大流)
- vue-router3路由配置一 路由搭建
- SpringBoot+Thymeleaf图片上传
- python小练习--GUI基础
- 华为从服务器获取安装包信息失败,华为系统恢复获取安装包信息失败
- 计算机专业个人年度总结,计算机教学年度个人工作总结
- 查询期刊的ISO版缩写的巧妙方法
热门文章
- The constness of a method should makes sense from outside the object
- PL/pgSQL的RETURN QUERY例子
- JS数据结构第五篇 --- 二叉树和二叉查找树
- HDU 2815 扩展baby step giant step 算法
- Java自学之路(新手一定要看)
- 为什么要关闭数据库连接,可以不关闭吗?
- 拿到参考资料的预训练模型,太可怕了!
- BERT meet Knowledge Graph:预训练模型与知识图谱相结合的研究进展
- 【文本匹配】Question Answering论文
- 【python】os 模块使用笔记