题解:洛谷 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
【核心思想】
-
问题分析:给定一个 \(N \times N\) 的 01 点阵图案(行末无空格),需要按照从左到右、从上到下的顺序,统计连续相同数字(
0或1)的段长,生成压缩码。压缩码的第一个数字是 \(N\),后续数字依次是各连续段的长度(第一个段从0开始)。本质是一个游程编码(RLE)压缩问题,只需逐字符扫描输入,统计连续相同字符的数量。 -
算法选择:
- 逐字符统计:由于输入是连续的字符流(包含换行符,但
cin >> c会跳过空白字符),可以直接读取每个非空白字符。维护一个计数器数组ans记录每个连续段的长度,以及当前字符lastC。当字符变化时,新建一个段;当字符相同时,增加当前段的计数。 - N 的获取:输入总字符数 \(len = N \times N\),因此 \(N = \sqrt{len}\)。在代码中,
sqrt(len)用于计算 \(N\) 并作为压缩码的第一个数字。
- 逐字符统计:由于输入是连续的字符流(包含换行符,但
-
关键步骤:
- 初始化:设置
lastC = '0'(因为第一个段统计的是0的数量),cnt = 0,ans[0] = 0。 - 读取与统计:使用
while (cin >> c)读取每个字符(包括换行后的字符):len++(记录总字符数)。- 若
c == lastC,则当前段计数ans[cnt]++。 - 否则,
cnt++,设置ans[cnt] = 1,更新lastC = c。
- 输出:先输出
sqrt(len),然后按顺序输出ans[0]到ans[cnt],用空格分隔。
- 初始化:设置
-
时间/空间复杂度:
- 时间复杂度:\(O(N^2)\),需要读取所有字符。
- 空间复杂度:\(O(N^2)\),用于存储各段的长度(最坏情况为 \(N^2\) 段,但通常远小于此)。
-
模拟与游程编码:
- 段首为 0:题目保证压缩码第一个数表示连续
0的个数,因此初始化lastC = '0'是正确的。 - 换行处理:
cin >> c会跳过空格和换行符,因此可以无缝处理多行输入。 - N 的计算:由于输入总字符数为 \(N^2\),且 \(N\) 是整数,
sqrt(len)可以精确得到 \(N\)(注意浮点数精度,但len是整数且是平方数,使用sqrt是安全的)。 - 适用场景:这类“游程编码压缩”问题是数据压缩的入门练习,也常见于模拟题。
- 段首为 0:题目保证压缩码第一个数表示连续
【算法标签】
入门 #模拟
【代码详解】
#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
浙公网安备 33010602011771号