ACM:最大盈利

 

主要实现思路

  1. 整体流程思路
    • 程序旨在处理多本账本(对应多个测试用例)中记录的每日盈亏数据,针对每本账本找出其中连续若干天盈利最多的情况(也就是连续子数组的最大和),并按照规定格式输出相应的账本标识、最大盈利数值以及对应的起始和终止日期编号。整体通过外层循环依次处理每个测试用例来达成目标,在每个测试用例内部又经过数据读取、最大盈利计算以及结果输出等步骤完成相应功能。
  2. 具体步骤思路
    • 初始化阶段
      • 首先通过 scanf("%d", &T); 读取测试用例的数量 T(表示账本数量,最多 20 本)。
      • 接着进入 for (int t = 1; t <= T; t++) 循环,针对每一个测试用例(每本账本):
        • 通过 scanf("%d", &N); 读取当前账本对应的整数数组的长度 N(范围是 1 到 100000)。
        • 然后使用 malloc 函数动态分配能存储 N 个 int 类型元素的内存空间,并将返回的指针赋值给 a,以此来创建一个长度根据输入 N 动态确定的数组(解决了原代码中变长数组可能存在的兼容性问题),同时进行内存分配失败的判断,如果分配失败则输出错误信息并终止程序。
        • 之后使用循环 for (int i = 0; i < N; i++) { scanf("%d", &a[i]); } 依次读取这 N 个整数并存入动态分配的数组 a 中。
        • 还初始化了一些关键变量,将 maxsum(记录连续子数组最大和)、nowsum(记录当前正在计算的连续子数组和)初始化为数组的第一个元素 a[0],将 start(当前正在计算的连续子数组起始位置)、beststart(最终最大和子数组的起始位置)、bestend(最终最大和子数组的结束位置)都初始化为 0。
    • 最大盈利计算阶段
      • 通过 for (int i = 1; i < N; i++) 循环从数组的第二个元素(索引为 1)开始遍历数组 a,以计算连续子数组的最大和以及对应的起始和结束位置。
      • 在循环中:
        • 当发现 nowsum < 0 时,意味着前面计算的这部分连续子数组和是负数,对后续求最大和没有帮助,所以需要重新开始计算,将 nowsum 重置为当前元素 a[i],并把 start 更新为当前索引 i
        • 若 nowsum >= 0,则将当前元素 a[i] 累加到 nowsum 中,继续扩展当前正在计算的连续子数组。
        • 每次更新 nowsum 后,判断 nowsum > maxsum 是否成立,如果成立,表示找到了一个更大的连续子数组和,此时更新 maxsum 为 nowsum,并记录这个更大和的连续子数组的起始位置 beststart(赋值为 start)和结束位置 bestend(赋值为当前索引 i)。
    • 结果输出阶段
      • 当完成对一个账本(一个测试用例)的处理后,先通过 printf("Payoff %d:\n", t); 输出账本号标识(按照格式要求)。
      • 再通过 printf("%d %d %d\n", maxsum, beststart + 1, bestend + 1); 输出最大盈利(即 maxsum)、最大盈利起始编号(beststart + 1,因为数组索引从 0 开始,实际编号要加 1)以及终止编号(bestend + 1)。
      • 最后判断如果当前测试用例不是最后一个(t < T),则通过 printf("\n"); 输出一个空行,用于分隔不同账本(测试用例)的输出结果,使输出格式符合要求。
    • 内存释放阶段
      • 在完成一个测试用例的所有操作后,通过 free(a); 释放之前使用 malloc 函数动态分配的内存空间,避免出现内存泄漏问题,然后继续处理下一个测试用例,直到所有测试用例都处理完毕。

 

#include <stdio.h>
#include <stdlib.h>

int main()
{
    // T用于存储测试用例的数量,即账本的数量,最多不超过20
    int T;  
    // 读取测试用例数量T
    scanf("%d", &T);  

    // 循环处理每个测试用例,t表示当前测试用例的序号,从1开始到T结束
    for (int t = 1; t <= T; t++) {
        // N用于存储每个账本(即每个测试用例对应的整数数组)中元素的数量,范围是1到100000
        int N;  
        // 读取当前测试用例对应的整数数组的长度N
        scanf("%d", &N);  

        // 使用malloc动态分配内存来存储数组元素,确保可以根据运行时输入的N来确定数组大小
        // 分配成功后,a指向一段连续的内存空间,用于存储N个int类型的元素,相当于创建了一个长度为N的整型数组
        int *a = (int *)malloc(N * sizeof(int));  
        // 判断内存分配是否失败,如果a为NULL,表示内存分配失败
        if (a == NULL) {  
            // 如果内存分配失败,输出错误信息并退出程序
            printf("Memory allocation failed!\n");  
            return 1;  
        }

        // 循环读取当前账本(测试用例)中的N个整数,并存入通过malloc分配的内存空间中(即数组a中)
        for (int i = 0; i < N; i++) {  
            scanf("%d", &a[i]);  
        }

        // maxsum用于记录到目前为止找到的连续子数组的最大和,初始化为数组的第一个元素a[0]
        int maxsum = a[0];  
        // nowsum用于记录当前正在计算的连续子数组的和,初始也设为数组的第一个元素a[0]
        int nowsum = a[0];  
        // start用于记录当前正在计算的连续子数组的起始位置,初始设为0
        int start = 0;  
        // beststart用于记录最终找到的具有最大和的连续子数组的起始位置,初始设为0
        int beststart = 0;  
        // bestend用于记录最终找到的具有最大和的连续子数组的结束位置,初始设为0
        int bestend = 0;  

        // 从数组的第二个元素(索引为1)开始遍历数组,计算连续子数组的最大和以及对应的起始和结束位置
        for (int i = 1; i < N; i++) {
            // 如果当前连续子数组的和小于0,说明前面这部分子数组对后续求最大和没有帮助,需要重新开始计算
            // 所以将当前和nowsum重置为当前元素a[i],并更新起始位置start为当前索引i
            if (nowsum < 0) {  
                nowsum = a[i];
                start = i;
            }
            // 如果当前连续子数组的和不小于0,则将当前元素累加到当前和nowsum中,继续扩展当前子数组
            else {  
                nowsum += a[i];
            }

            // 如果当前连续子数组的和大于之前记录的最大和maxsum,说明找到了一个更大的连续子数组和
            // 则更新最大和maxsum为当前和nowsum,并记录这个更大和的连续子数组的起始位置beststart和结束位置bestend
            if (nowsum > maxsum) {  
                maxsum = nowsum;
                beststart = start;
                bestend = i;
            }
        }

        // 输出当前账本(测试用例)对应的信息,先输出账本号标识
        printf("Payoff %d:\n", t);  
        // 再输出最大盈利(即最大和maxsum)、最大盈利起始编号(beststart + 1,因为数组索引从0开始,实际编号要加1)以及终止编号(bestend + 1)
        printf("%d %d %d\n", maxsum, beststart + 1, bestend + 1);  

        // 如果当前测试用例不是最后一个(t < T),则输出一个空行,用于分隔不同账本(测试用例)的输出结果
        if (t < T)  
            printf("\n");

        // 使用完动态分配的内存后,释放内存,防止内存泄漏,释放之前通过malloc分配的内存空间
        free(a);  
    }
    return 0;
}

 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值