hdu1081 DP类最大子段和(二维压缩+前缀和数组/树状数组计数)
2015-03-02 19:54
477 查看
题意:给出一个 n * n 的数字矩阵,问最大子矩阵和是多少。
由于和最长子段和问题类似,一开始想到的就是 DP ,一开始我准备用两个循环进行 DP ,对于每一个 (i,j) ,考察(i - 1,j)与(i,j - 1), dp 值代表以该点为右下角的最大矩阵和,同时记录下这个矩阵的左上角坐标,状态转移时通过将原和最大矩阵通过补边推到当前和最大矩阵。但是其实这种做法有一个明显的问题,就是转移时,补上边后 dp 值相同怎么办,dp 值相同而矩阵不同的话会影响到下一次状态转移后补上的矩阵的情况,从而影响到下一个矩阵的判断。
并想不出怎么做的我无奈看了题解……二维压缩,好吧,并不懂那是个什么……细看之下才知道,其实就是用数组记录下矩阵后,在 dp 时对于起始结束行不同的矩阵分别 DP ,记录下其中最大值即可。例如对于所有列,考虑其前两行的情况,即子矩阵行数为 2 ,这时每列的两个数可以计算其和为一个数,就能将二维的矩阵转化为一维的数组了,这样再进行与最长子段和相同的操作就能得出答案了。
当然,记录矩阵并且便于计算行之间的和,我用了前缀和数组和树状数组两种方式。这题明显用前缀和数组更加好,因为输入的数不会发生改变,所以前缀和数组更加容易计算,用树状数组做并不是用来体现我的逼格高,只是因为我个人树状数组基本没有在题目中用过几次,所以这次敲一遍训练一下,以免以后遇到了明明会但是敲不出来或者敲得太慢……说白了就是弱……
前缀和数组:
View Code
由于和最长子段和问题类似,一开始想到的就是 DP ,一开始我准备用两个循环进行 DP ,对于每一个 (i,j) ,考察(i - 1,j)与(i,j - 1), dp 值代表以该点为右下角的最大矩阵和,同时记录下这个矩阵的左上角坐标,状态转移时通过将原和最大矩阵通过补边推到当前和最大矩阵。但是其实这种做法有一个明显的问题,就是转移时,补上边后 dp 值相同怎么办,dp 值相同而矩阵不同的话会影响到下一次状态转移后补上的矩阵的情况,从而影响到下一个矩阵的判断。
并想不出怎么做的我无奈看了题解……二维压缩,好吧,并不懂那是个什么……细看之下才知道,其实就是用数组记录下矩阵后,在 dp 时对于起始结束行不同的矩阵分别 DP ,记录下其中最大值即可。例如对于所有列,考虑其前两行的情况,即子矩阵行数为 2 ,这时每列的两个数可以计算其和为一个数,就能将二维的矩阵转化为一维的数组了,这样再进行与最长子段和相同的操作就能得出答案了。
当然,记录矩阵并且便于计算行之间的和,我用了前缀和数组和树状数组两种方式。这题明显用前缀和数组更加好,因为输入的数不会发生改变,所以前缀和数组更加容易计算,用树状数组做并不是用来体现我的逼格高,只是因为我个人树状数组基本没有在题目中用过几次,所以这次敲一遍训练一下,以免以后遇到了明明会但是敲不出来或者敲得太慢……说白了就是弱……
前缀和数组:
#include<stdio.h> #include<string.h> #define max(a,b) a>b?a:b int t[101][101],dp[101],n; void add(int i,int j,int d){ while(j<=n){ t[i][j]+=d; j+=(j&-j); } return; } int sum(int k,int x){ int cnt=0; while(x>0){ cnt+=t[k][x]; x-=(x&(-x)); } return cnt; } int main(){ while(scanf("%d",&n)!=EOF&&n!=0){ int i,j,k,ans=-0xFFFFFFF,tmp; memset(t,0,sizeof(t)); for(i=1;i<=n;i++){ for(j=1;j<=n;j++){ scanf("%d",&tmp); add(i,j,tmp); } } for(i=0;i<=n-1;i++){ for(j=i+1;j<=n;j++){ memset(dp,0,sizeof(dp)); for(k=1;k<=n;k++){ tmp=sum(k,j)-sum(k,i); if(dp[k-1]>0){ dp[k]=dp[k-1]+tmp; } else dp[k]=tmp; ans=max(ans,dp[k]); } } } printf("%d\n",ans); } return 0; }
View Code
相关文章推荐
- hdu 1081 最大子矩阵(二维前缀和优化)@
- HDU-1081-To The Max(二维最大子段和)
- hdu 1081 (最大子段和的升级版,二维)
- hdu——1081(二维最大连续和)
- 最大子段和系列(二维子段和、环形数组子段和、最大m段和) 思路
- hdu 1559 最大子矩阵(二维树状数组)
- POJ-2155 Matrix 二维树状数组, HDU-3584 Cube 三维树状数组
- HDU-1081 To The Max 二维最大子序列和
- 2016 ACM/ICPC Reginal Shengyang hdu 5892 -Resident Evil 二维树状数组 + 状态压缩
- 【二维树状数组】hdu 1559 最大子矩阵
- HDU 1081 To The Max(最大连续子序列和(二维))
- hdu 1081 To The Max(二维最大连续和)
- hdu 1081 To The Max(暴力枚举+最大连续子数组和)
- HDU 1081 To The Max(二维最大字段和,转化为一维)
- HDU 1003 Max Sum && HDU 1081 To The Max 一维子串最大和& 二维矩阵最大和
- HDU 1024 最大M子段和 滚动数组优化
- HDU 1081 最大子矩阵(LCS_DP+前缀和)
- hdu 1081 利用前缀和求最大字段和
- hdu 1559 最大子矩阵(二维树状数组)
- 51Nod 1081 子段求和(数组/树状数组)