题解:学而思编程 降雨统计

【题目来源】

学而思编程:降雨统计

【题目描述】

最近正值雨季,小猴希望通过观察气象云图来预测城市每个未知的降雨时间。

小猴所在的城市可以看成一个 \(n\times m\) 的矩阵 \(a\)\(a_{i,j}\) 表示城市中的每一个地区,该地区上空的天气情况共有两种情况:

  1. 晴空万里:用字符 . 表示,表示该地区无降雨;
  2. 乌云密布:用字符 # 表示,表示该地区正在降雨。

据小猴观察,乌云以每分钟 \(1\) 个方格的速度向右移动,乌云到达某地区时,该地区就会有降雨过程,乌云离开后,降雨停止。假设 \(0\) 时刻时,城市最左边缘以左的部分都是晴天。

现在给定初始时刻(\(t=0\))的每个地区上空天气情况,请你帮助小猴统计每个地区的降雨时间是多少分钟。

【输入】

第一行两个正整数 \(n,m\)

接来来 \(n\) 行,每行 \(m\) 个字符,每个字符对应该地区上空天气情况。

【输出】

\(n\) 行,每行 \(m\) 个数字,用空格隔开,表示 \(a_{i,j}\) 对应地区的总降雨时间。

【输入样例】

3 3
..#
###
.#.

【输出样例】

0 0 1
1 2 3
0 1 1

【核心思想】

  1. 问题分析:给定 \(n \times m\) 的天气矩阵,. 表示晴天,# 表示降雨。乌云以每分钟 \(1\) 格的速度向右移动,\(t=0\) 时最左边缘以左为晴天。求每个地区的总降雨时间。这是一个前缀累加问题,关键在于理解乌云移动规律:每个 # 会对其右侧所有位置产生 \(1\) 分钟的降雨贡献。

  2. 算法选择

    • 行内前缀累加:乌云向右移动,同一行中每个 # 会使其自身及右侧所有位置降雨时间 \(+1\)
    • 逐行统计:对每行从左到右扫描,维护当前累计的 # 数量,即为该位置的降雨时间
  3. 关键步骤

    • 初始化:读取 \(n\)(行数)和 \(m\)(列数)
    • 读取天气矩阵 a[0..n-1][0..m-1]
    • 逐行计算降雨时间
      • 遍历 \(i\)\(0\)\(n-1\)(每行):
        • sum = 0:当前行累计的 # 数量
        • 遍历 \(j\)\(0\)\(m-1\)(每列):
          • a[i][j] == '#'sum++(遇到乌云,累计数加 \(1\)
          • 输出 sum(当前位置的降雨时间 = 左侧及自身的 # 数量)
        • 输出换行
  4. 时间/空间复杂度

    • 时间复杂度:\(O(n \times m)\),遍历整个矩阵一次
    • 空间复杂度:\(O(n \times m)\),存储天气矩阵
  5. 前缀累加的核心思想

    • 乌云移动建模:乌云以速度 \(1\) 向右移动,\(t=0\) 时位于初始 # 位置。对于位置 \((i, j)\),所有列号 \(\leq j\)# 都会在某个时刻移动到 \(j\),因此降雨时间等于该行中从第 \(0\) 列到第 \(j\) 列的 # 数量
    • 前缀和等价sum 即为前缀和,表示当前位置及左侧所有 # 的总数,每个 # 贡献 \(1\) 分钟降雨
    • 行间独立性:乌云只在行内水平移动,各行互不影响,可独立计算
    • 边界条件:最左边缘以左为晴天,无需额外处理;矩阵右边缘外无位置,最后一个 # 只影响自身位置
    • 适用于"一维移动源 + 覆盖计数"类问题,前缀累加将复杂的时间模拟转化为空间扫描

【算法标签】

模拟

【代码详解】

#include <bits/stdc++.h>
using namespace std;

int main()
{
    int n, m;
    cin >> n >> m;  // 输入矩阵的行数和列数

    char a[n][m];  // 声明字符矩阵

    for (int i = 0; i < n; i++)  // 处理每一行
    {
        cin >> a[i];  // 输入第i行字符串
    }

    char s;  // 这个变量定义了但没有使用
    int sum;  // 统计每行的'#'数量

    for (int i = 0; i < n; i++)  // 遍历每一行
    {
        sum = 0;  // 每行开始时重置计数器
        for (int j = 0; j < m; j++)  // 遍历该行的每个字符
        {
            if (a[i][j] == '#')  // 如果当前字符是'#'
            {
                sum++;  // 计数器加1
            }
            cout << sum << " ";  // 输出当前位置的累计'#'数量
        }
        cout << endl;  // 每行结束后换行
    }

    return 0;
}

【运行结果】

3 3
..#
0 0 1
###
1 2 3
.#.
0 1 1
posted @ 2026-07-04 14:59  团爸讲算法  阅读(5)  评论(0)    收藏  举报