To the Max-动态规划 树状数组
来源:互联网 发布:舒同 书法 知乎 编辑:程序博客网 时间:2024/05/18 00:24
To the Max
问题来源:hdu-1050
Description
Given a two-dimensional array of positive and negative integers, a sub-rectangle is any contiguous sub-array of size 1*1 or greater located within the whole array. The sum of a rectangle is the sum of all the elements in that rectangle. In this problem the sub-rectangle with the largest sum is referred to as the maximal sub-rectangle.
As an example, the maximal sub-rectangle of the array:
0 -2 -7 0
9 2 -6 2
-4 1 -4 1
-1 8 0 -2
is in the lower left corner:
9 2
-4 1
-1 8
and has a sum of 15.
Input
The input consists of an N * N array of integers. The input begins with a single positive integer N on a line by itself, indicating the size of the square two-dimensional array. This is followed by N^2 integers separated by whitespace (spaces and newlines). These are the N^2 integers of the array, presented in row-major order. That is, all numbers in the first row, left to right, then all numbers in the second row, left to right, etc. N may be as large as 100. The numbers in the array will be in the range [-127,127].
Output
Output the sum of the maximal sub-rectangle.
Sample Input
4
0 -2 -7 0
9 2 -6 2
-4 1 -4 1
-1 8 0 -2
Sample Output
15
源代码一(普通DP):
代码分析:从上面的这段代码我们能很明显地看出时间复杂度很高,主函数里for嵌套4层,并且求和的阶段s[m]+=map[k][m]是最频繁的一句代码,求和部分很频繁,为了节约时间,我改成了二维的树状数组来实现求和,因为树状数组求和的复杂度时O(logn)的,比起O(n)的普通求和节约了不少时间
源代码二(二维树状数组求和):
代码分析:由代码对比,很明显地看出树状数组的下标需要从1开始,从0开始是实现不了的(至少说不好实现),树状数组将求和的复杂度从O(n)降为了O(logn),但是得多开辅助存储空间C数组,这也就是经常遇到的消耗空间来节省时间(动态规划从一定意义上说就是部分深度优先搜索的节省消耗空间来节省时间的优化),对树状数组的发明者表示衷心地佩服!
问题来源:hdu-1050
Description
Given a two-dimensional array of positive and negative integers, a sub-rectangle is any contiguous sub-array of size 1*1 or greater located within the whole array. The sum of a rectangle is the sum of all the elements in that rectangle. In this problem the sub-rectangle with the largest sum is referred to as the maximal sub-rectangle.
As an example, the maximal sub-rectangle of the array:
0 -2 -7 0
9 2 -6 2
-4 1 -4 1
-1 8 0 -2
is in the lower left corner:
9 2
-4 1
-1 8
and has a sum of 15.
Input
The input consists of an N * N array of integers. The input begins with a single positive integer N on a line by itself, indicating the size of the square two-dimensional array. This is followed by N^2 integers separated by whitespace (spaces and newlines). These are the N^2 integers of the array, presented in row-major order. That is, all numbers in the first row, left to right, then all numbers in the second row, left to right, etc. N may be as large as 100. The numbers in the array will be in the range [-127,127].
Output
Output the sum of the maximal sub-rectangle.
Sample Input
4
0 -2 -7 0
9 2 -6 2
-4 1 -4 1
-1 8 0 -2
Sample Output
15
源代码一(普通DP):
#include<iostream>using namespace std;const int MAX = 100;int map[MAX][MAX];int s[MAX] , num , N;int dp( void );int main( ){ int ans , max; while( cin>>N ){ max = 0; //数组下表从0开始 for( int i=0 ; i<N ; i++ ) for( int j=0 ; j<N ; j++ ) cin>>map[i][j]; for( int i=0 ; i<N ; i++ ){ //i遍历每一行 for( int j=i ; j<N ; j++ ){ //j遍历i之后的每一行 for( int m=0 ; m<N ; m++ ){ //m是对于每一列来说 s[m] = 0; //初始化 for( int k=i ; k<=j ; k++ ) s[m] += map[k][m]; //叠加和 } ans = dp( ); //求最大子序列之和 if( ans>max ) max = ans; } } cout<<max<<endl; } return 0;}int dp( void ){ int sum=0 , max=0; for( int i=0 ; i<N ; i++ ){ //O(n)的复杂度 sum += s[i]; if( sum < 0 ) //小于0就赋值为0 sum = 0; if( sum > max ) max = sum; //记录最大值 } return max;}
代码分析:从上面的这段代码我们能很明显地看出时间复杂度很高,主函数里for嵌套4层,并且求和的阶段s[m]+=map[k][m]是最频繁的一句代码,求和部分很频繁,为了节约时间,我改成了二维的树状数组来实现求和,因为树状数组求和的复杂度时O(logn)的,比起O(n)的普通求和节约了不少时间
源代码二(二维树状数组求和):
#include<iostream>using namespace std;const int MAX = 100;int map[MAX][MAX];int s[MAX] , C[MAX][MAX] , num , N;//C是求和的累加数组int dp( void );int lowbit( int n ); //管辖域int sum( int col , int n ); //返回A[1]到A[n]的和void add( int k , int col , int n ); //更新C数组的个元素int main( ){ int ans , max; while( cin>>N ){ max = 0; memset( C , 0 , sizeof( C ) ); for( int i=1 ; i<=N ; i++ ) //下标改成从0开始,因为树状数组不是从0的开始的,否则管辖域为0; for( int j=1 ; j<=N ; j++ ){ cin>>map[i][j]; add( i , j , map[i][j] ); } for( int i=1 ; i<=N ; i++ ){ for( int j=i ; j<=N ; j++ ){ for( int m=1 ; m<=N ; m++ ) s[m] = sum( m , j ) - sum( m , i-1 ); //求该段之和 ans = dp( ); if( ans>max ) max = ans; } } cout<<max<<endl; } return 0;}int dp( void ){ int sum=0 , max=0; for( int i=0 ; i<N ; i++ ){ //和上一个函数一样 sum += s[i]; if( sum < 0 ) sum = 0; if( sum > max ) max = sum; } return max;}int lowbit( int n ){ return n & ( -n ); //管辖域就是n对应的二进制数从后往前第一个1所在位置是k(第一个位置是0),则管辖域就是2^k}void add( int k , int col , int n ){ while( k <= N ){ C[col][k] += n; //累加更新 k += lowbit( k ); //"父结点" }}int sum( int col , int n ){ int ss = 0; while( n ){ ss += C[col][n]; //求和 n -= lowbit( n ); //回到另一个点的管辖域范围内 } return ss;}
代码分析:由代码对比,很明显地看出树状数组的下标需要从1开始,从0开始是实现不了的(至少说不好实现),树状数组将求和的复杂度从O(n)降为了O(logn),但是得多开辅助存储空间C数组,这也就是经常遇到的消耗空间来节省时间(动态规划从一定意义上说就是部分深度优先搜索的节省消耗空间来节省时间的优化),对树状数组的发明者表示衷心地佩服!
0 0
- To the Max-动态规划 树状数组
- To The Max(动态规划)
- POJ 1050-To the Max (动态规划)
- hdu 1081 To The Max (动态规划)
- To the Max(动态规划DP)
- POJ 1050 To the Max -- 动态规划
- HDU 1081 To The Max 动态规划
- poj1050 To the Max (动态规划)
- 三维动态规划 To The Max
- POJ1050 To the Max 动态规划
- zoj1074 TO THE MAX(动态规划)
- 【动态规划】[POJ 1050]To the Max
- POJ1050 To the Max 简单动态规划
- 动态规划之To the Max
- Pku acm 1050 To the Max 【动态规划】
- acm pku 1050 To the Max的动态规划方法
- 动态规划入门——To The Max
- To the Max(动态规划DP)
- HDU 1003 max sum
- Could not resolve archetype org.apache.maven.archetypes:maven-archetype-quickstart:
- Mongodb简介
- Hadoop 权限管理
- nyoj 461
- To the Max-动态规划 树状数组
- 视频主观质量评价工具:MSU Perceptual Video Quality tool
- C#属性与字段
- Python快速入门
- android中ContactsContract类的使用
- ESD对电子设备造成的困扰
- 静态区间第k大数
- thinkphp3.2开发排错一例——当__APP__的值变化后,需要删除缓存~runtime.php文件
- 孪生素数问题