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. odoo 8.0 多核启用

    对于很多企业来说,随着时间的推移,用户量或者企业建点扩张,使用erp就会出现应用访问越来越慢的情况, 其实这种情况不但限于erp,只要是有数据量增长的互联网业务必然会遇到的,因为一开始的是就没有做好大 ...

  2. 网站被攻击扫描SQL注入的日常记录

    我发了个博客,泄露了域名之后,便有人疯狂的尝试攻击我的站点,奈何我防守做得比较好,直接把网段封了,看到403还锲而不舍,我真是想给他颁奖了 查看ua,发现很多sqlmap的ua,肯定会是被刷了,只是运 ...

  3. java-日期类

    一 显示系统时间 package cn.itcast.api.a.date; import java.text.DateFormat; import java.util.Date; public cl ...

  4. 低价替代Vector CANoe CAN总线适配解决方案支持所有USBCAN(周立功CAN、PCAN、Kvaser、ValueCAN、NI CAN)

    在汽车通信领域CAN总线使用非常广泛,最强大的工具有Vector Case(10WRMB).Pcan(2KRMB),ZLGCAN(1.5KRMB),KVASER(2KRMB).ValueCAN(4KR ...

  5. CSS Tools: Reset CSS

    样式初始化 /* http://meyerweb.com/eric/tools/css/reset/ v2.0 | 20110126 License: none (public domain) */ ...

  6. AOP Aspect 统一日志、异常处理、数据格式 【转】

    package com.gsww.chis.aop; import java.util.Arrays; import com.google.common.base.Throwables; import ...

  7. Swift 之类的继承与类的访问权限

    http://www.cocoachina.com/swift/20160104/14821.html 上一篇博客<窥探Swift之别具一格的Struct和Class>的博客可谓是给Swi ...

  8. malloc: *** error for object 0x10a291df8: pointer being freed was not allocated *** set a breakpoint in malloc_error_break to debug

    malloc_error_break错误: .You'll find out what the object is when you break in the debugger. Just look ...

  9. Mysql+php报错原因

    SQL syntax --语法错误,看near,错误会在near后引号中的内容 的附近 Table/Database....... dosen't existes ---表/库(库名/表名) 不存在 ...

  10. 单行中文字和图片的相关height和line-height特性

    这几天在做仿京东的产品页,发现在制作过程中的一些问题,需要好好研究下. 需要实现的效果如上图所示: 在写CSS样式的时候,对于我的关于竖线的做法是: 设置高度为14,border样式,但导致了一个问题 ...