51nod 1051 最大子矩阵和 【最大子段和DP变形/降维】
【题目】:
一个M*N的矩阵,找到此矩阵的一个子矩阵,并且这个子矩阵的元素的和是最大的,输出这个最大的值。
例如:*3的矩阵: - -
-
- 和最大的子矩阵是: -
- Input
第1行:M和N,中间用空格隔开( <= M,N <= )。
第2 - N + 1行:矩阵中的元素,每行M个数,中间用空格隔开。(-^ <= M[i] <= ^)
Output
输出和的最大值。如果所有数都是负数,就输出0。
Input示例 - -
-
-
Output示例
【分析】:
在做这道题之前必须会最大子段和这一道题的基础,这也是动态规划中最简单的一道例题,而这道题是最大字段和的一个扩展。
例子: 0,2,7,2,-5最大的一个连续子序列之和。
分析:这五个数有这样几种和的组合:0;02;027;0272;……这样5!个数。
用数组索引来表示就是:0;0到1;0到2;0到3……1;1到2;……(这里是数组索引表示)
我们显然不能用多重循环把所有数都算出来,我们换一种角度思考,如果只有一个数字,那么最大的连续子序列数多少,还是以上面的例子为例,应该是0吧,那么现在有两个数字呢?有两种情况,一种是前面有一个数字的最大值(已求)+现在这个数字;另外一种情况是就是只有这个数字;然后算出来的最大值与只有一个数字的情况的最大值相比较;现在有三个数字,也有两种情况,一种是前面有前面两个数字的最大值+现在这个数字;或者就是只是这个数字;……
第一行:N代表这个N*N矩阵的维数 int max_sum(int n)
{
int i, sum = 0, max = INT_MIN;
for(i = 0; i < n; i++)
{ -------------------------------------------------------------------------------0
if(sum < 0)
sum = 0;
sum += a[i]; ---------------------------------------------------------1
if(sum > max)
max = sum;---------------------------------------------------------2
}
return max;
}
----0----代表蓝色部分【这个不用说循环】
----1----代表橙色部分【**下面说**】
----2----代表紫色部分
我们橙色的字;因为一共有两种情况,一种是自己本身,一种是前i-1项的最大值,我们换个思路想一下,假如第1个数(索引为0的数)为负数,那么下面前两个数的最大最一定是第二个数其本身,即第二次是把sum=0;sum+=a[1] 然后记录max值。。。实际上就是假如你前n个数是正的那么可以继续加上去,如果你前n个数是负的那么把值记录一下就好了。所以只要求前n项和和最大值就好了。
当然也有人是这样写的:
int MaxSum(int n,int *a)
{
int sum=0,b=0;
for(int i=1; i<=n; i++)
{
if(b>0)
{
b+=a[i];
}
else
{
b=a[i];
}
if(b>sum)
{
sum = b;
}
}
return sum;
}
或者更加直白的话是这样写的,这样更加容易理解一些,看个人的编程习惯了:
int max_sum2(int n)
{
b[0]=a[0]; //数组b存放前n项的最大值
int maximal=b[0];
for(int i=1;i<n;i++)
{
b[i]=max(b[i-1]+a[i],a[i]); //STL
if(b[i]>maximal)
maximal=b[i];
}
return maximal;
}
下面写二维的矩阵这道题,我们首先要做的就是降维然后像上面一样做。
科幻小说《三体》中描绘了恢弘壮丽的“降维攻击”的场景:
“歌者”随手抛下了一张“二向箔”,整个银河系的三维空间奔腾汹涌地流入二向箔,塌缩成一个二维平面,三维结构被碾压在二维平面之上。同时,这一降维过程是全息的,所有的三维信息被保留在碾压后的二维空间里。这种致命的攻击令攻击者和被攻击者同归于尽,玉石俱焚,其结局黑暗得令人窒息。
我们知道,在线性空间的最大子段和,已有线性时间的DP算法。有没有可能,把二维的最大矩阵和转化为一维的最大子段和呢?
答案是肯定的,算法有着似三体描述的未来武器般的威力
对于一个子矩阵,有四个属性:起始行位置 i , 结束行位置 j, 起始列 x, 结束列 y
我们可以枚举i, j, 然后对后列进行降维压缩
再对降维后的一维数组进行最大子序列和动态规划就行了。
#include<cstdio>
#include<cstring>
#include<queue>
#include<iostream>
#include<stack>
#define maxn 505
#define maxm 50005
#define INF 0x3f3f3f3f
#define ll long long
using namespace std; int n,m;
int a;
int dp[maxn][maxn];
//int sum[maxn][maxn]; int main()
{
while(cin>>m>>n)
{
memset(dp,,sizeof(dp));
for(int i=;i<=n;i++){
for(int j=;j<=m;j++){
scanf("%d",&a);
dp[i][j]=dp[i-][j]+a;////让dp存放第i行的前j项和
//其实我们用数学之美来看为什么要这样存放,你一维的时候存放的是一维的数据
//二维的时候再存放一维的数据就是错误的,二维的时候就应该存放二维的数据
//当然你也不要去存放前i行前j列之和,这个相比于前面的就是三维的数据了
//如果你算的是长方体的数据,这样应该是对的,那么我们的数组也应该是三维的了
}
}
//s数组是用来记录起点行到终点行的每一竖条的数值和的,ans是用来记录不同的子矩阵和的(需要相邻竖条相加),
int ans=;
for(int i=;i<=n;i++){//这n行数有这样几种和的组合:0;02;027;0272;……这样n!个数。
//用数组索引来表示就是:0;0到1;0到2;0到3……1;1到2;……(这里是数组索引表示)
for(int j=i;j<=n;j++){//前面两层循环是列循环,比如三列的话就是,1-2列,1-3列,2-3列
int sum=;
for(int k=;k<=m;k++){
sum+=(dp[j][k]-dp[i-][k]);//对i到j行矩阵进行降维操作
if(sum<) sum=;
if(sum>ans) ans=sum;
//ans=max(ans,sum);
}
}
}
printf("%d\n",ans);
}
return ;
}
注意行列n,m输入顺序
51nod 1051 最大子矩阵和 【最大子段和DP变形/降维】的更多相关文章
- 51nod 1051 最大子矩阵和(dp)
题目链接:51nod 1051 最大子矩阵和 实质是把最大子段和扩展到二维.读题注意m,n... #include<cstdio> #include<cstring> #inc ...
- 51nod 1051 最大子矩阵和
没想到居然可以O(n3)暴力过 就是大概之前的 最大连续子序列和 加成2维度了 枚举起始列 和 终止列 然后计算从1到n行最大的子矩阵的和 注意n 和 m 的输入顺序!! #include< ...
- 51nod 1051 最大子矩阵和(DP)
题意 略 分析 一道经典的DP题,但是我弱到差点做不出来,真的垃圾 设置\(sum(i,j)代表1-i行第j列的前缀和\),然后枚举行i和行j,再枚举列k,做一遍类似一维的最大子段和即可 #inclu ...
- 【模板】51nod 1051 最大子矩阵和
[题解] 二重循环枚举起始列和终止列,竖着往下加,转化为一个最大子段和问题,逐行累加即可. #include<cstdio> #include<cstring> #includ ...
- 51nod 1051 求最大子矩阵和
题目链接:http://www.51nod.com/onlineJudge/questionCode.html#!problemId=1051 1051 最大子矩阵和 基准时间限制:2 秒 空间限制: ...
- 最大子矩阵和 51Nod 1051 模板题
一个M*N的矩阵,找到此矩阵的一个子矩阵,并且这个子矩阵的元素的和是最大的,输出这个最大的值. 例如:3*3的矩阵: -1 3 -1 2 -1 3 -3 1 2 和最大的子矩阵是: 3 - ...
- 51Nod 1050 循环数组最大子段和 | DP
Input示例 6 -2 11 -4 13 -5 -2 Output示例 20 分析: 有两种可能,第一种为正常从[1 - n]序列中的最大子字段和:第二种为数组的total_sum - ([1-n] ...
- 51nod 1051
* 最大子矩阵 * sum[i][j] 表示第 i 行前 j 列的和,即每一行的前缀 * i,j 指针枚举列,k指针枚举行 * Now 记录当前枚举的子矩阵的价值 * 由于记录了前缀信息,一旦 Now ...
- 51nod 1051【基础】
思路: 找题4级做做...然后找了题最水的.. = =感动...居然是一下子[记]得了做法... dp一下,枚举列的起点和终点,然后求和这一段,然后对这一大列就是求个最大字段和: #include & ...
随机推荐
- java和c/c++
写c/c++的人,羡慕java可以自己管理内存 写java的人,羡慕c/c++没有gc问题
- 跟着学!教你开发第一个Java程序
今天我们的目标是开发人生中的第一个Java程序,虽然可能会很简单,但是这小小的一步却是跨入IT行业的一大步!下面我们来一起来仔细的了解开发的流程. 准备工作 1,作为一名准程序猿自备一台电脑那是必不可 ...
- 《Cracking the Coding Interview》——第8章:面向对象设计——题目2
2014-04-23 17:45 题目:假设有个呼叫中心,有接线员.经理.主管三种角色.如果接线员无法处理呼叫,就上传给经理:如果仍无法处理,则上传给主管.请用代码描述这一过程. 解法:第一眼觉得这题 ...
- Hyper-V 安装Windows 2008,08 R2,12 R2 无网卡驱动的解决办法
最近玩 Hyper -V ,都是在网上找的资料进行操作的.后面发觉园友提供的一些操作 按部就班的做下来,别人 可以 ,我的就是不行. 最近就遇到一个很烦闷的事情.(如题) 安装好系统之后 发现 没有网 ...
- mongodb导入json文件(WINDOWS)
mongodb导入json格式的文件的命令是mongoimport: 在下面的这个例子中,使用mongoimport命令将文件pi.json中的内容导入loacal数据库的pi集合中. 打开CMD,进 ...
- 常用模块(random)
import randomimport string# dt = random.randint(1,2) # 从1-2间取随机数,包括1.2# dt = random.randrange(1,3) # ...
- python 学习分享-实战篇高级的ftp
#server代码 import socketserver,os,hashlib Base_paht = os.path.dirname(os.path.dirname(os.path.abspath ...
- 孤荷凌寒自学python第二十天python的匿名函数与偏函数
孤荷凌寒自学python第二十天python的匿名函数与偏函数 (完整学习过程屏幕记录视频地址在文末,手写笔记在文末) Python为使函数的使用更加方便高效,可以使用两种特殊的函数简化语句书写. 一 ...
- 01、dos命令行的常用命令
cd 进入指定目录cd.. 返回上一级目录cd\ 退回盘符根目录dir 列出当前目录下的文件以及文件夹md 创建目录rd 删除目录del 删除文件cls ...
- 牛客小白月赛4——I—合唱队形
链接:https://www.nowcoder.com/acm/contest/134/I来源:牛客网 题目描述 铁子的班级在毕业晚会有一个合唱节目,到了毕业晚会的时候,他们必须排成一排一起合唱&qu ...