UVa 235 Typesetting
题目描述
本题要求实现一个文本排版系统,支持可变宽度字体和不同字号。输入包含字体宽度表和多个段落,需要根据给定的行宽对每个段落进行排版,并输出排版结果。
问题分析
输入格式
-
字体宽度表:
- 第一行:字符数量 N
- 接下来 N 行:每行包含一个字符和6个整数,表示该字符在6种字体下10点字号时的宽度
-
段落数据:
- 每段以 “L W” 开头,L 是文本行数,W 是允许的行宽
- 后续 L 行是段落文本
- 以 “0 0” 结束输入
特殊标记
*fN
:切换字体(N=1-6)*sN
:切换字号(N=1-99)
输出要求
对于每个段落的每一行:
- 行号
- 该行的第一个和最后一个单词
- 行尾的空白空间(如果单词超出行宽则为负值)
算法思路
关键点
-
字符宽度计算:
- 实际宽度 = (10点字号宽度 × 当前字号 + 5) / 10
- 使用整数运算避免浮点精度问题
-
单词处理流程:
- 遇到特殊标记时更新字体和字号
- 计算每个单词的宽度
- 判断单词是否能放入当前行
- 处理超长单词(单独占一行)
-
行构建策略:
- 尽可能多地放入单词
- 单词间插入空格宽度
- 记录每行的首尾单词
核心步骤
- 初始化:读取字体表,建立字符到索引的映射
- 段落处理:
- 合并所有输入行
- 按单词处理文本流
- 跟踪当前字体、字号和行状态
- 输出格式:按要求输出段落号和每行信息
代码实现
// Typesetting
// UVa ID: 235
// Verdict: Accepted
// Submission Date: 2025-10-06
// UVa Run Time: 0.010s
//
// 版权所有(C)2025,邱秋。metaphysis # yeah dot net#include <bits/stdc++.h>using namespace std;int font[110][10];
map<char, int> idx;
int paragraph = 1;
int L, W;void process(string lines) {int printedLines = 1;int size = 1, point = 10;int currentWidth = 0, spaceWidth;string firstWord, lastWord, word;istringstream iss(lines);cout << "Paragraph " << paragraph++ << '\n';while (iss >> word) {if (word[0] == '*') {if (word[1] == 'f') size = stoi(word.substr(2));if (word[1] == 's') point = stoi(word.substr(2));continue;}int wordWidth = 0;for (int i = 0; i < word.length(); i++)// use integer instead of round function, or you will get 'Wrong Answer'wordWidth += (font[idx[word[i]]][size] * point + 5) / 10;if ((currentWidth && currentWidth + spaceWidth + wordWidth >= W) || wordWidth >= W) {if (currentWidth) {cout << "Line " << printedLines++ << ": " << firstWord << " ... " << lastWord;cout << " (" << (W - currentWidth) << " whitespace)\n";currentWidth = 0;}if (wordWidth >= W) {cout << "Line " << printedLines++ << ": " << word;if (wordWidth == W) cout << " ... " << word;cout << " (" << (W - wordWidth) << " whitespace)\n";wordWidth = 0;}}if (currentWidth) currentWidth += spaceWidth;else firstWord = word;if (wordWidth) {currentWidth += wordWidth;lastWord = word;}// use integer instead of round function, or you will get 'Wrong Answer'spaceWidth = (font[idx[' ']][size] * point + 5) / 10;}if (currentWidth) {cout << "Line " << printedLines++ << ": " << firstWord << " ... " << lastWord;cout << " (" << (W - currentWidth) << " whitespace)\n";}
}int main(int argc, char *argv[]) {string line;getline(cin, line);int n = stoi(line);for (int i = 1; i <= n; i++) {getline(cin, line);istringstream iss(line);if (line.front() == ' ') idx.insert(make_pair(' ', i));else {char character;iss >> character;idx.insert(make_pair(character, i));}for (int j = 1; j <= 6; j++) iss >> font[i][j];}while (getline(cin, line)) {istringstream iss(line);iss >> L >> W;if (L == 0) break;string allLines; for (int i = 1; i <= L; i++) {getline(cin, line);allLines += line + ' ';}process(allLines);}return 0;
}
总结
本题主要考察字符串处理和模拟能力,需要注意:
- 字符宽度的整数计算方法
- 特殊标记的识别和处理
- 行构建时的边界条件判断
- 输出格式的精确控制
通过合理的数据结构和清晰的逻辑流程,可以高效解决这类文本处理问题。