nyoj 44 子串和 & nyoj 104 最大和

来源:互联网 发布:transmit mac 破解 编辑:程序博客网 时间:2024/04/30 13:49

子串和

时间限制:5000 ms  |  内存限制:65535 KB
难度:3
描述
给定一整型数列{a1,a2...,an},找出连续非空子串{ax,ax+1,...,ay},使得该子序列的和最大,其中,1<=x<=y<=n。
输入
第一行是一个整数N(N<=10)表示测试数据的组数)
每组测试数据的第一行是一个整数n表示序列中共有n个整数,随后的一行里有n个整数I(-100=<I<=100),表示数列中的所有元素。(0<n<=1000000)
输出
对于每组测试数据输出和最大的连续子串的和。
样例输入
151 2 -1 3 -2
样例输出
5

一道需要很注意的题。用的是贪心策略:用max保存一段区间的最大值。一边输入一边看看当前连续区间的和sum是不是大于了max,如果大了,就更新max。注意,此时的sum没有被更新,而是继续累加。这样就完成了连续区间这一要求。    可能会问:这样求的不是从第一个数开始的最大子串和么? 如果是从第二数开始的某一子串和才是最大的怎么办?这时,就要想:这些全都是数啊,如果都是正数,肯定全加起来才是最大的。但问题就是这里边会有负数。所以,从第i开始的子串和最大的情况,只可能是前i-1个数的和为负数,不然不可能舍弃这一段数的

 #include <iostream>#include <stdio.h>#include <algorithm>using namespace std;int a[1000003];int main(){    int t, n, i, sum, max;    scanf("%d", &t);    while(t--)    {        scanf("%d", &n);        scanf("%d", &a[0]);        sum = a[0];        max = a[0];//max一定要足够小。因为可能有负数。        if(sum < 0)//这个一定要有,不然输入-2,1……就会出错,1不能被存入了。            sum = 0;        for(i = 1 ; i < n ; i++)        {            scanf("%d", &a[i]);            sum += a[i];             if(sum > max)                max = sum;            if(sum < 0)                sum = 0;        }        printf("%d\n", max);    }    return 0;}        


最大和

时间限制:1000 ms  |  内存限制:65535 KB
难度:5
描述

给定一个由整数组成二维矩阵(r*c),现在需要找出它的一个子矩阵,使得这个子矩阵内的所有元素之和最大,并把这个子矩阵称为最大子矩阵。 
例子:
0 -2 -7 0 
9 2 -6 2 
-4 1 -4 1 
-1 8 0 -2 
其最大子矩阵为:

9 2 
-4 1 
-1 8 
其元素总和为15。 

输入
第一行输入一个整数n(0<n<=100),表示有n组测试数据;
每组测试数据:
第一行有两个的整数r,c(0<r,c<=100),r、c分别代表矩阵的行和列;
随后有r行,每行有c个整数;
输出
输出矩阵的最大子矩阵的元素之和。
样例输入
14 40 -2 -7 0 9 2 -6 2 -4 1 -4 1 -1 8 0 -2 
样例输出
15

利用上一题的思想,这一题也可以用类似的贪心解出来。

乍眼一看,这题和上一题差不多啊,但是怎么把二维转化为一维呢?因为要想办法把矩阵转化为一行的这种数组,所以就想到压缩,假如要求一个两行的矩阵的最大子矩阵,那么就可以先求出第一行的最大子串和,然后把数组一列对一列地叠加,更新后的t再求最大子串和,就是以第一行起始的所有矩阵的最大子矩阵了,因为最大子矩阵就是数字加起来和最大!

用i控制总循环次数,表示:这一次求的是起始行必为i,但终止行(j)和宽度(k)随意的所有矩形中最大的。这里矩形数字和的求法是在同i的条件下,用t数组保存一行,即把上几行的数组压缩成一个t,像摞饼一样- - 一层一层叠加上,列于列对应,然后求t的最大子串和,也就是被压缩的矩阵中的最大矩阵。然后求以所有起始行开始的所有最大值中的最大值即为所求。

#include <iostream>#include <stdio.h>#include <string.h>#include <algorithm>using namespace std;int r, c, a[105][105];int findmax(int t[]){    int max = t[1], sum = 0, i;    for(i = 1 ; i <= c ; i++)//必须从1开始。如果从2开始,假如是-2,1……就会出错    {        sum += t[i];        if(sum > max)            max = sum;        if(sum < 0)            sum = 0;    }    return max;}int main(){    int n, i, j, k, max, t[105], s;    scanf("%d", &n);    while(n--)    {        scanf("%d %d", &r, &c);        for(i = 1 ; i <= r ; i++)            for(j = 1 ; j <= c ; j++)            scanf("%d", &a[i][j]);        max = a[1][1];        for(i = 1 ; i <= r ; i++)        {            memset(t, 0, sizeof(t));            for(j = i ; j <= r ; j++)            {                for(k = 1 ; k <= c ; k++)                    t[k] = t[k] + a[j][k];                s = findmax(t);                if(s > max)                    max = s;            }        }        printf("%d\n", max);    }    return 0;}


0 0
原创粉丝点击