HDU 1081 To The Max【dp,思维】
题意:给定二维矩阵,求数组的子矩阵的元素和最大是多少。
题解:这个相当于求最大连续子序列和的加强版,把一维变成了二维。
先看看一维怎么办的:
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,思维】的更多相关文章
- URAL 1146 Maximum Sum & HDU 1081 To The Max (DP)
点我看题目 题意 : 给你一个n*n的矩阵,让你找一个子矩阵要求和最大. 思路 : 这个题都看了好多天了,一直不会做,今天娅楠美女给讲了,要转化成一维的,也就是说每一列存的是前几列的和,也就是说 0 ...
- 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 ...
- HDU 1081 To The Max (dp)
题目链接 Problem Description Given a two-dimensional array of positive and negative integers, a sub-rect ...
- hdu 1081 To The Max(二维压缩的最大连续序列)(最大矩阵和)
Problem Description Given a two-dimensional array of positive and negative integers, a sub-rectangle ...
- HDU 1081 To the Max 最大子矩阵(动态规划求最大连续子序列和)
Description Given a two-dimensional array of positive and negative integers, a sub-rectangle is any ...
- 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 ...
- Hdu 1081 To The Max
To The Max Time Limit: 2000/1000 MS (Java/Others) Memory Limit: 65536/32768 K (Java/Others)Total ...
- HDU 2476 String painter(区间DP+思维)
题目链接:http://acm.hdu.edu.cn/showproblem.php?pid=2476 题目大意:给你字符串A.B,每次操作可以将一段区间刷成任意字符,问最少需要几次操作可以使得字符串 ...
- HDU 1081 To The Max(动态规划)
题目链接 Problem Description Given a two-dimensional array of positive and negative integers, a sub-rect ...
随机推荐
- php 5.3 iis php_memcache 安装不上
有的服务器很扯淡,安装了很长时间的php_memcache 扩展 始终安装不上 具体原因不清楚 因为 php_memcache.dll php 官网上只有 最新支持的版本 例如 http://pecl ...
- openCV图像合成
#include <iostream> #include <opencv2/opencv.hpp> #include <opencv2/highgui/highgui.h ...
- 解决C++ builder 4.0编译后的程序在某些计算机上运行出现"EAccessViolation" 的错误
1. bordbk41.dll is missing or not registered. regsvr32 "C:\Program Files (x86)\Common Files\Bor ...
- TZ_16_Vue_入门案例
1.新建一个html文件导入vue.js <script src="node_modules/vue/dist/vue.js"></script> 2.创建 ...
- HTML,CSS,JS优化
HTML部分 语义化HTML:好处在于可以使代码简洁清晰,支持不同设备,利于搜索引擎,便于团队开发: 减少DOM节点:加速页面渲染: 给图片加上正确的宽高值:这可以减少页面重绘,同时防止图片缩放: 防 ...
- Java基础-注解
什么是注解? Jdk1.5新增新技术,注解.很多框架为了简化代码,都会提供有些注解.可以理解为插件,是代码级别的插件,在类的方法上写:@XXX,就是在代码上插入了一个插件. 注解不会也不能影响代码的实 ...
- java-异常处理2
一 编译时异常和运行时异常的区别 java认为如果你的程序有问题,你应该让调用者知道. 例如:面包,长毛了.用户去买了,用户可能会挂 .应该在面包上贴上标签(异常). java 如果在函数内抛出Exc ...
- python实例 条件和循环语句
#! /usr/bin/python #条件和循环语句 x=int(input("Please enter an integer:")) if x<0: x=0 ...
- 简单的layui二级联动
用layui实现省市二级联动, 需要注意的是使用layui之后, 你看到的下拉选框就不是option了,而是一些div 1.select表单 2.JS, ajax返回的是普通的数组
- 基于 DataLakeAnalytics 的数据湖实践
随着软硬件各方面条件的成熟,数据湖(Data Lake)已经越来越受到各大企业的青睐, 与传统的数仓实践不一样的是,数据湖不需要专门的“入仓”的过程,数据在哪里,我们就从哪里读取数据进行分析.这样的好 ...