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 ...
随机推荐
- Leetcode144. Binary Tree Preorder Traversal二叉树的前序遍历
给定一个二叉树,返回它的 前序 遍历. 示例: 输入: [1,null,2,3] 1 \ 2 / 3 输出: [1,2,3] 进阶: 递归算法很简单,你可以通过迭代算法完成吗? 递归: class S ...
- c++新特性实验(4)声明与定义:右值引用(C++11)
1.作用 c++11以前,临时对象.字面常量一般情况下不可以再次访问,也不可以修改.右值引用可以解决这个问题. 1.1 实验A #include <iostream> using name ...
- TZ_01MyBatis_log4j.propertiies
# Set root category priority to INFO and its only appender to CONSOLE. #log4j.rootCategory=INFO, CON ...
- css3正方体效果
<!doctype html> <html> <head> <meta charset="utf-8"> <title> ...
- Linux下读写UART串口的代码
Linux下读写UART串口的代码,从IBM Developer network上拿来的东西,操作比較的复杂,就直接跳过了,好在代码能用,记录一下- 两个实用的函数- //////////////// ...
- Javascript实现信息滚动效果的方法
<html><head><meta http-equiv="Content-Type" content="text/html; charse ...
- 2019阿里云开年Hi购季云通信分会场全攻略!
2019阿里云云上Hi购季活动已经于2月25日正式开启,从已开放的活动页面来看,活动分为三个阶段: 2月25日-3月04日的活动报名阶段.3月04日-3月16日的新购满返+5折抢购阶段.3月16日-3 ...
- Google earth爬取卫星影像数据并进行标注路网的方法
一.下载goole earth 和GetScreen: 试了很多,找了可以使用的上传到百度网盘,链接如下所示: 链接:https://pan.baidu.com/s/1fp-W8u68iRsJ0xcu ...
- LINUX下C++编程如何获得某进程的ID
#include <stdio.h> #include <stdlib.h> #include <unistd.h> using namespace std; pi ...
- 第十章—DOM(0)—NODE类型
DOM1定义了一个node接口,该接口由DOM的所有节点类型实现. 所有的节点都存在这样或那样的关系.在HTML中,head,body可以看出是html的子元素,html是head,body的父元素, ...