HDU 1081

题意:给定二维矩阵,求数组的子矩阵的元素和最大是多少。

题解:这个相当于求最大连续子序列和的加强版,把一维变成了二维。

先看看一维怎么办的:

 int getsum()
{
int tot=;
int ans=-1e9;
for(int i=;i<=n;i++){
if(tot<) tot=;
tot+=a[i];
if(tot>ans)
ans=tot;
}
return ans;
}

这种做法太棒了!短短几行,就能解决最大子序列和这个问题。其实这几行代码值得深思。而且这是个在线算法,输入数据及时能给出结果,感觉不能归于动归解法。

  但当求解这道题时,就不知道怎么办了。我当时受到以前做的一道关于求01矩阵最大0子矩阵面积的题的启发,想先预处理每行得到前缀和数组,然后再想办法dp。可是dp状态和方程一直找不好。后来看到别人的解法才明白,他们其实也是预先处理的每行的前缀和。他们的想法就是先求出每行的前缀和数组sum[][],然后依次枚举前k行的第i列到第j列的和,求最大值。感觉就像是枚举出了每一个子矩阵,像暴力>_<.

#include<iostream>
#include<cstdio>
#include<cstring>
#include<algorithm>
using namespace std;
const int MAXN = ;
int sum[MAXN][MAXN]; int main()
{
int N, tmp;
while (scanf("%d", &N) == )
{
memset(sum, , sizeof(sum));
for (int i = ; i <= N; i++)
for (int j = ; j <= N; j++)
{
scanf(" %d", &tmp);
sum[i][j] = sum[i][j - ] + tmp;//预处理得到每行的前缀和
}
int ans = -1e9;
for (int i = ; i <= N; i++) {//从第i列
for (int j = i; j <= N; j++) {//到第j列
int tot = ;
for (int k = ; k <= N; k++)//前k行
{
if (tot < ) tot = ;
tot += sum[k][j] - sum[k][i - ];//第i列到第j列的和
if (ans < tot)
ans = tot;
}
}
}
printf("%d\n", ans);
}
return ;
}

当然,可以前k行第i列到第j列就可以前k列第i行到第j行,其实是一样的:

 #include<iostream>
#include<cstdio>
#include<cstring>
#include<algorithm>
using namespace std;
const int MAXN = ;
int sum[MAXN][MAXN]; int main()
{
int N,tmp;
while (scanf("%d",&N)==)
{
memset(sum, , sizeof(sum));
for(int i=;i<=N;i++)
for (int j = ; j <= N; j++)
{
scanf(" %d", &tmp);
sum[i][j] = sum[i-][j] + tmp;
}
int ans = -1e9;
for (int i = ; i <= N; i++) {
for (int j = i; j <= N; j++) {
int tot = ;
for (int k = ; k <= N; k++)
{
if (tot < ) tot = ;
tot += sum[j][k] - sum[i-][k];
if (ans < tot)
ans = tot;
}
}
}
printf("%d\n", ans);
}
return ;
}

按前k列想

也有人按照矩阵压缩的想法写,我觉得实际上还是上面的做法,而且上面的想法更容易理解。因为这里所谓矩阵压缩也就是几行加在一起求最大连续子序列。虽殊途同归,但毕竟想法不一样,代码上就会稍微有点差别:

 #include<iostream>
#include<cstring>
#include<cstdio>
#include<algorithm>
using namespace std;
const int MAXN=;
int a[MAXN][MAXN],tmp[MAXN];
int N; int getsum()
{
int tot=,mx=;
for(int i=;i<=N;i++){
tot+=tmp[i];
if(tot>mx) mx=tot;
if(tot<) tot=;
}
return mx;
} int main()
{
while(scanf("%d",&N)==)
{
int temp;
for(int i=;i<=N;i++)
for(int j=;j<=N;j++)
scanf("%d",&a[i][j]);
int ans=-1e9;
for(int i=;i<=N;i++)
{
memset(tmp,,sizeof(tmp));
for(int j=i;j<=N;j++)
{
for(int k=;k<=N;k++)
tmp[k]+=a[j][k];
int tot=getsum();
if(ans<tot)
ans=tot;
}
}
printf("%d\n",ans);
} return ;
}

按矩阵压缩的想法

还有人用树状数组写,我觉的也很棒。没想到我第一次用到二维树状数组是再做dp题的时候。。。虽然这是伪装成二维树状数组的,因为只更新了一维。按照我的理解二维树状数组就是存了若干个一维树状数组的和。

 #include<iostream>
#include<cstring>
#include<cstdio>
#include<algorithm>
using namespace std;
const int MAXN=;
int sum[MAXN][MAXN]={};
int N; int Lowbit(int x)
{
return x&-x;
} void Add(int i,int j,int val)
{
while(j<=N){
sum[i][j]+=val;
j+=Lowbit(j);
}
return;
} int Sum(int k,int x)
{
int cnt=;
while(x>){
cnt+=sum[k][x];
x-=Lowbit(x);
}
return cnt;
} int main()
{
while(scanf("%d",&N)==)
{
int tmp;
memset(sum,,sizeof(sum));
for(int i=;i<=N;i++)
for(int j=;j<=N;j++){
scanf("%d",&tmp);
Add(i,j,tmp);
}
int ans=-1e9;
for(int i=;i<=N;i++)
{
for(int j=i;j<=N;j++){
int tot=;
for(int k=;k<=N;k++){
if(tot<) tot=;
tot+=Sum(k,j)-Sum(k,i-);
if(ans<tot)
ans=tot;
}
}
}
printf("%d\n",ans);
} return ;
}

当然,加个dp数组看起来更像是dp题。

 #include<iostream>
#include<cstdio>
#include<cstring>
#include<algorithm>
using namespace std;
const int MAXN = ;
int sum[MAXN][MAXN];
int dp[MAXN];
int N; int lowbit(int x)
{
return x&-x;
} void add(int i, int j, int d)
{
while (j <= N)
{
sum[i][j] += d;
j += lowbit(j);
}
return;
} int Sum(int k, int x)
{
int cnt = ;
while (x>)
{
cnt += sum[k][x];
x -= lowbit(x);
}
return cnt;
} int main()
{
int tmp;
while (scanf("%d",&N)==)
{
memset(sum, , sizeof(sum));
for(int i=;i<=N;i++)
for (int j = ; j <= N; j++)
{
scanf(" %d", &tmp);
add(i, j, tmp);
}
int ans = -1e9;
for (int i = ; i <= N; i++) {
for (int j = i; j <= N; j++) {
memset(dp, , sizeof(dp));
for (int k = ; k <= N; k++) {
tmp = Sum(k, j) - Sum(k, i-);
if (dp[k - ] > )
dp[k] = dp[k - ] + tmp;
else
dp[k] = tmp;
ans = max(ans, dp[k]);
}
}
}
printf("%d\n", ans);
}
return ;
}

加个dp[]数组

参考博客(感谢~):

【1】:http://blog.csdn.net/acmman/article/details/38580931?spm=5176.100239.blogcont18950.3.TbcH0h

【2】:http://www.cnblogs.com/cenariusxz/p/4309627.html

【3】:http://www.cnblogs.com/gaigai/archive/2012/03/04/2379728.html

HDU 1081 To The Max【dp,思维】的更多相关文章

  1. URAL 1146 Maximum Sum & HDU 1081 To The Max (DP)

    点我看题目 题意 : 给你一个n*n的矩阵,让你找一个子矩阵要求和最大. 思路 : 这个题都看了好多天了,一直不会做,今天娅楠美女给讲了,要转化成一维的,也就是说每一列存的是前几列的和,也就是说 0 ...

  2. hdu 1081 To The Max(dp+化二维为一维)

    题目链接:http://acm.hdu.edu.cn/showproblem.php?pid=1081 To The Max Time Limit: 2000/1000 MS (Java/Others ...

  3. HDU 1081 To The Max (dp)

    题目链接 Problem Description Given a two-dimensional array of positive and negative integers, a sub-rect ...

  4. hdu 1081 To The Max(二维压缩的最大连续序列)(最大矩阵和)

    Problem Description Given a two-dimensional array of positive and negative integers, a sub-rectangle ...

  5. HDU 1081 To the Max 最大子矩阵(动态规划求最大连续子序列和)

    Description Given a two-dimensional array of positive and negative integers, a sub-rectangle is any ...

  6. dp - 最大子矩阵和 - HDU 1081 To The Max

    To The Max Problem's Link: http://acm.hdu.edu.cn/showproblem.php?pid=1081 Mean: 求N*N数字矩阵的最大子矩阵和. ana ...

  7. Hdu 1081 To The Max

    To The Max Time Limit: 2000/1000 MS (Java/Others)    Memory Limit: 65536/32768 K (Java/Others)Total ...

  8. HDU 2476 String painter(区间DP+思维)

    题目链接:http://acm.hdu.edu.cn/showproblem.php?pid=2476 题目大意:给你字符串A.B,每次操作可以将一段区间刷成任意字符,问最少需要几次操作可以使得字符串 ...

  9. HDU 1081 To The Max(动态规划)

    题目链接 Problem Description Given a two-dimensional array of positive and negative integers, a sub-rect ...

随机推荐

  1. 关于dex 64K 引用限制

    1.官方文档 https://developer.android.com/studio/build/multidex 主要内容: 什么是64K限制 编码时如何避免64K 限制 拆分dex避免64K 限 ...

  2. Web App开发注意事项

    1.首先我们来看看webkit内核中的一些私有的meta标签,这些meta标签在开发webapp时起到非常重要的作用 <meta content=”width=device-width, ini ...

  3. hdu 1505 && hdu1506 &&hdu 2830 && 2870 总结---------DP之状图选最大矩形

    /* 多谢了“闭眼,睁眼” 同学给我一套dp专题,不然真是没接触过这种题型. 做个4个简单的,很高兴有所收获. 2013-08-06 /* HDU 1506 最基础的一道题目,其主要精髓就在于两个数组 ...

  4. LintCode_114 不同的路径,115 不同的路径 II

    题目 有一个机器人的位于一个M×N个网格左上角(下图中标记为'Start'). 机器人每一时刻只能向下或者向右移动一步.机器人试图达到网格的右下角(下图中标记为'Finish'). 问有多少条不同的路 ...

  5. 因子分析spss怎么做 spss因子分析教程及结果解释

    因子分析spss怎么做 spss因子分析教程及结果解释 因子分析spss可以简化数据结构,将具有错综复杂关系的变量综合为数据较少的因子,在信息损失最小的情况下对变量进行分类,不过有些朋友多spss因子 ...

  6. nslookup查不到数据

    ch查不到数据 换一个ip就可以了,什么原理?

  7. netbeans7.4 在项目内查找 快捷键 ctrl shift f

  8. MySQL错误1055

    问题描述:在MySQL数据库下,执行SQL插入语句报错.错误信息如下: 错误原因:在MySQL5.7之后,sql_mode中默认存在ONLY_FULL_GROUP_BY,SQL语句未通过ONLY_FU ...

  9. MarioTCP, take it..

    MrioTCP,超级马里奥,顾名思义,他不仅高效,而且超级简易和好玩.同时他可以是一个很简洁的Linux C 开发学习工程.毫不夸张的说,如果全部掌握这一个工程,你会成为一个Linux C的牛人:当然 ...

  10. Leetcode590N-ary Tree Postorder TraversalN叉树的后序遍历

    给定一个 N 叉树,返回其节点值的后序遍历. class Node { public: int val; vector<Node*> children; Node() {} Node(in ...