若是(最大子矩阵和)

题目描述
“一生至少该有一次,为了某个人而忘了自己,不求有结果,不求同行,不求曾经拥有,甚至不求你爱我,只求在我最美的年华里,遇到你。”——徐志摩

原来小W和小K要到到Q镇去游玩。

Q镇是一个非常浪漫的约会圣地,同时它也是一个很特别的城镇。

小镇中有很多道路,四通八达。它有n+1条的小路为南北方向,有m+1条的小路为东西方向,这些道路将Q镇划分成了m×n个区域,而这些区域,从北到南、从西到东的坐标标识为从坐标(1,1)到坐标(m,n)。

小W和小K在网上找到了情侣们对这m×n个区域的打分V(i,j)(分数可正可负)。分数越高表示那个区域越适合情侣们出没,越低表示不适合情侣游玩。为了方便游玩,小W和小K决定选定一个连续的区域集合作为他们的游玩范围。例如,如果他们选择了最西北的区域(m1
,n1)和最东南(m2,n2)区域(m1≤m2,n1≤n2),那么他们的活动范围是(i,j)∣(m1≤i≤m2,n1≤j≤n2)},他们游玩的欢乐值则为这些活动范围的区域评分总和。

小W和小K希望他们游玩范围内的区域的欢乐值最大。

而身为单身狗的你的任务是编写一个程序,求出他们的活动范围(m1,n1),(m2,n2)的欢乐值的最大值。

输入
输入第一行为整数m,n,用空格隔开
接下来有m行,每行有n列整数,其中第i行第j列的整数,代表V(i,j),一个整数之间用空格隔开。输入数据保证这些整数中,至少存在一个正整数。

输出
输出只有一行,为最高的欢乐值。

样例输入
4 5
1 -2 3 -4 5
6 7 8 9 10
-11 12 13 14 -15
16 17 18 19 20

样例输出
146

提示
对于100%的数据,1≤N,M≤200,且V(i,j)∈[−200000,200000]。

官方题解:
  观察题目,也许有人会毫不犹豫的选择枚举,将所有的 m1,n1,m2,n2 的情况全部求出来,但哪怕将查询区间 {D(i,j) (m1≤i≤m2,n1≤j≤n2)} 的分值的速度优化到 O(1),这都是过不了的。因此,我们需要寻找一种更优秀的暴力方法。
  首先,我们可以很容易知道,对于一个正确的 m1,n1,m2,n2 满足条件,该区域每个边上的所有分值和必然大于0.因为如果其某边的分值和小于0,则可以通过删除该边以得到更优的解。扩展一下,该区域必然可以分成两个矩形,并且两个矩形的分值都会大于0,否则我们将删除小于0的分值的矩形以得到更高的分数。那么,我们就可以得到一个优秀的条件,就是我们在搜索的过程中,得到的任意一个矩形的分值都大于0,否则我们就抛弃它。
  因此,我们可以通过这个特殊的条件,来减少复杂度。
  我们可以枚举它的最左边的位置和最右边的位置,也就是n1,n2。
因为,假设存在这样一个m1,n1,m2,n2,我们枚举的n1,n2必然有一种情况会与最优解相同。
  那么,由于我们再枚举m1,m2必然会导致时间复杂度过高,那么,我们就可以选择只枚举一遍 m’,在枚举的过程中进行计算。我们使得枚举过程中,maxn记录下存在枚举的m’行所形成的最大值,若是maxn大于0,我们就继续枚举,并且考虑它是否是最优解,也就是将maxn与答案ans进行对比。
  如果maxn小于0,根据我们刚才上述的条件,上面枚举的矩形都将直接抛弃,maxn重新设为0,继续寻找合适的矩形。
通过这种方法,复杂度会变成 O(n^3),就可以解决本题了。

思路
用最大矩阵和的方法解决问题

首先要求矩阵的前缀和,累加要求区间的矩阵前缀和之差,当累加值小于0时,将累加值归0,得到累加值的最大值,即为答案

代码实现

#include <iostream>
#include <cstdio>
#include <algorithm>
#include <queue>
#include <string>
#include <cstring>
using namespace std;
typedef long long ll;
const int N=205;
int m,n,v[N][N];
int ans;
int main()
{
    scanf("%d%d",&m,&n);
    for(int i=1;i<=m;i++)
        for(int j=1;j<=n;j++)
        {
            scanf("%d",&v[i][j]);
            v[i][j]+=v[i][j-1];
        }
    for(int i=1;i<=n;i++)
    {
        for(int j=i;j<=n;j++)
        {
            int tmp=0;
            for(int k=1;k<=m;k++)
            {
                tmp+=v[k][j]-v[k][i-1];
                if(tmp<0) tmp=0;
                if(tmp>ans) ans=tmp;
            }
        }
    }
    printf("%d\n",ans);
    return 0;
}

猜你喜欢

转载自blog.csdn.net/weixin_43935894/article/details/88095841