C++一本通在线测评网站 题目1224

发布于:2023-01-07 ⋅ 阅读:(479) ⋅ 点赞:(0)

注:该程序本人已提交网站并通过,希望提供一定帮助。

原题目:最大子矩阵

【题目描述】1224

已知矩阵的大小定义为矩阵中所有元素的和。给定一个矩阵,你的任务是找到最大的非空(大小至少是1×1)子矩阵。

【输入】

输入是一个N×N的矩阵。输入的第一行给出N(0<N<=100)。再后面的若干行中,依次(首先从左到右给出第一行的N个整数,再从左到右给出第二行的N个整数……)给出矩阵中的N2个整数,整数之间由空白字符分隔(空格或者空行)。已知矩阵中整数的范围都在[−127,127]。

【输出】

输出最大子矩阵的大小。

【输入样例】

4

 0 -2 -7  0

 9  2 -6  2

-4  1 -4  1

-1  8  0 -2

【输出样例】

15

理解:                                                                                                                                                 本题考查二维数组的使用与变化和少量的算法应用,逻辑较为简单,其实就是一道关于矩阵的变化的题目。题目说明中指明要“矩阵”,所以我们就要保证我们在算法计算中每一步的本质性图形是个矩形(也就是长方形或正方形)。而为了尽量的减少时间复杂度,我们用两个数组。加之由递归式的思维得出的关于一维直线式求最大和需要2个循环的结论看出,我们做二维矩阵是可以用三循环做出的。(这里的的所谓“几循环”是指程序中维数最多的循环的维数,列如有一个程序,它有3个一循环和2个2循环,一个3循环,还有1个4循环,那么它就会被称作四循环程序)我们可以用一个变量ans每次算出这个子矩阵的总和,再依次作比较找出最大的即可。

应用:                                                                                                                                                 防止ans为0以下,ans大于nmax时赋值,其他按普通矩阵程序做就行了。思考时要注意二维的情况不好像,先从一维的判断最长线段开始推。

完整无标记程序(无批注):

#include<iostream> 
using namespace std;
long long a[1001][1001],b[1001][1001];
int main()
{
    int n,main=0,ans,nmax=-300;
    cin>>n;
    for(int i=1;i<=n;i++)
       for(int j=1;j<=n;j++)
       {
               cin>>a[i][j];
               main=main+a[i][j];
               b[i][j]=main;
       }
    for(int i=1;i<=n;i++)
       for(int j=1;j<=n;j++)
       {
               ans=0;
               for(int f=1;f<=n;f++)
            {
                ans=ans+b[f][j]-b[f][i-1];
                if(ans>nmax) nmax=ans;
                if(ans<0) ans=0;
            }
       }                                                                                                                                                    cout<<nmax;
    return 0;

程序注解(含批注):

#include<iostream>    //内容中含有输入(cin)和输出(cout)类的c++语句,因此要调用iostream库
using namespace std;  //保证程序的正常运行
int a[1001][1001],b[1001][1001];  //定义数组a和b,a数组用于输入时的单个数存储,范围不太大,最多也只有127,(题目原句:"
已知矩阵中整数的范围都在[−127,127]。" int数据类型是可以存储0和负数的)所以用int。b数组用于标记和计算前缀和
int main()  //main是主要的意思,意为主程序部分
{
    int n,main=0,ans,nmax=-300;  //定义边长n,用于算当前总和的mian,用于计算总量的ans,nmax可以和ans进行比较,从而求出最大的一个子矩阵的和,然后输出它
    cin>>n;   //输入边长n
    for(int i=1;i<=n;i++)  //双循环,一个i,一个j,输入整个矩阵
       for(int j=1;j<=n;j++)  //双循环,一个i,一个j,输入整个矩阵
       {
               cin>>a[i][j];  //输出当前这个位置上的数,存入a数组,i为纵坐标,j为横坐标
               main=main+a[i][j];  //main每次都增加,表示当前的总和,但它还不能直接计算前缀和,因此后面得再开一个三循环来分离每部分,算前缀和
               b[i][j]=main;  //当前总和存入b数组
       }
    for(int i=1;i<=n;i++)  //从左上角开始,每行每列的分离出矩形的一部分,计算比较前缀和
       for(int j=1;j<=n;j++)  //从左上角开始,每行每列的分离出矩形的一部分,计算比较前缀和
       {
               ans=0;  //每次计算比较前都要先清零ans,要不然上次的数据就还在里面,影响结果
               for(int f=1;f<=n;f++)  //不能重复,因此用f。这个循环的作用是保证分离出来的是矩形
            {
                ans=ans+b[f][j]-b[f][i-1];  //这个就是求前缀和的简单算法,我们由思考得出结论,举例子,从10到2的这部分的总和怎么计算开始思考,得出结论,算法是从10到1这部分的总和减去从0到的1的总和,代数式化后就变成了上面这句“ans=ans+b[f][j]-b[f][i-1];” 
                if(ans>nmax) nmax=ans;   //如果当前的和比之前记录的最大子矩阵和大的话,就重新赋值最大,代表ans刷新了nmax的最大记录,因此现在的最大记录就是ans。
                if(ans<0) ans=0;  //如果ans是个负数,就把它归零处理
            }
       }                                                                                                                                                      cout<<nmax;  //输出
    return 0;  //程序终止


网站公告

今日签到

点亮在社区的每一天
去签到