题解:洛谷 P1320 压缩技术(续集版)

【题目来源】

洛谷:P1320 压缩技术(续集版) - 洛谷

【题目描述】

设某汉字由 \(N\times N\)\(0\)\(1\) 的点阵图案组成。

我们依照以下规则生成压缩码。连续一组数值:从汉字点阵图案的第一行第一个符号开始计算,按书写顺序从左到右,由上至下。第一个数表示连续有几个 \(0\),第二个数表示接下来连续有几个 \(1\),第三个数再接下来连续有几个 \(0\),第四个数接着连续几个 \(1\),以此类推……

例如:以下汉字点阵图案:

0001000
0001000
0001111
0001000
0001000
0001000
1111111

对应的压缩码是\(7\ 3\ 1\ 6\ 1\ 6\ 4\ 3\ 1\ 6\ 1\ 6\ 1\ 3\ 7\) (第一个数是,其余各位表示交替表示 \(0\)\(1\) 的个数,压缩码保证 \(N\times N=\) 交替的各位数之和)

【输入】

汉字点阵图(点阵符号之间不留空格)。

【输出】

输出一行,压缩码。

【输入样例】

0001000
0001000
0001111
0001000
0001000
0001000
1111111

【输出样例】

7 3 1 6 1 6 4 3 1 6 1 6 1 3 7

【核心思想】

  1. 问题分析:给定一个 \(N \times N\) 的 01 点阵图案(行末无空格),需要按照从左到右、从上到下的顺序,统计连续相同数字(01)的段长,生成压缩码。压缩码的第一个数字是 \(N\),后续数字依次是各连续段的长度(第一个段从 0 开始)。本质是一个游程编码(RLE)压缩问题,只需逐字符扫描输入,统计连续相同字符的数量。

  2. 算法选择

    • 逐字符统计:由于输入是连续的字符流(包含换行符,但 cin >> c 会跳过空白字符),可以直接读取每个非空白字符。维护一个计数器数组 ans 记录每个连续段的长度,以及当前字符 lastC。当字符变化时,新建一个段;当字符相同时,增加当前段的计数。
    • N 的获取:输入总字符数 \(len = N \times N\),因此 \(N = \sqrt{len}\)。在代码中,sqrt(len) 用于计算 \(N\) 并作为压缩码的第一个数字。
  3. 关键步骤

    • 初始化:设置 lastC = '0'(因为第一个段统计的是 0 的数量),cnt = 0ans[0] = 0
    • 读取与统计:使用 while (cin >> c) 读取每个字符(包括换行后的字符):
      • len++(记录总字符数)。
      • c == lastC,则当前段计数 ans[cnt]++
      • 否则,cnt++,设置 ans[cnt] = 1,更新 lastC = c
    • 输出:先输出 sqrt(len),然后按顺序输出 ans[0]ans[cnt],用空格分隔。
  4. 时间/空间复杂度

    • 时间复杂度:\(O(N^2)\),需要读取所有字符。
    • 空间复杂度:\(O(N^2)\),用于存储各段的长度(最坏情况为 \(N^2\) 段,但通常远小于此)。
  5. 模拟与游程编码

    • 段首为 0:题目保证压缩码第一个数表示连续 0 的个数,因此初始化 lastC = '0' 是正确的。
    • 换行处理cin >> c 会跳过空格和换行符,因此可以无缝处理多行输入。
    • N 的计算:由于输入总字符数为 \(N^2\),且 \(N\) 是整数,sqrt(len) 可以精确得到 \(N\)(注意浮点数精度,但 len 是整数且是平方数,使用 sqrt 是安全的)。
    • 适用场景:这类“游程编码压缩”问题是数据压缩的入门练习,也常见于模拟题。

【算法标签】

入门 #模拟

【代码详解】

#include <bits/stdc++.h>  // 包含标准库头文件(万能头文件)
using namespace std;      // 使用标准命名空间

int ans[40005];          // 定义全局数组:存储连续相同字符的计数

int main()
{
    char c;              // 定义变量:当前读取的字符
    char lastC = '0';     // 定义变量:上一个字符(初始化为'0')
    int len = 0;         // 定义变量:输入字符总长度
    int cnt = 0;         // 定义变量:连续段计数器

    // 循环读取输入字符
    while (cin >> c)
    {
        len++;           // 总字符数加1

        // 判断当前字符是否与上一个字符相同
        if (c == lastC)
        {
            ans[cnt]++;  // 相同则当前连续段计数加1
        }
        else
        {
            cnt++;       // 不同则创建新连续段
            ans[cnt] = 1; // 新连续段计数初始化为1
            lastC = c;    // 更新上一个字符为当前字符
        }
    }

    // 输出总字符数的平方根(题目特殊要求)
    cout << sqrt(len);

    // 输出各连续段的字符数
    for (int i = 0; i <= cnt; i++)
    {
        cout << ' ' << ans[i];  // 用空格分隔输出各段计数
    }

    return 0;            // 程序正常结束
}

【运行结果】

0001000
0001000
0001111
0001000
0001000
0001000
1111111
7 3 1 6 1 6 4 3 1 6 1 6 1 3 7
posted @ 2026-08-31 09:24  团爸讲算法  阅读(9)  评论(0)    收藏  举报