CF70B Text Messaging 题解

题目传送门

题意简介

有以下递归定义:

消息 = 句子 or 句子 空格 消息
句子 = 单词 空格 句子 or 单词 结尾
结尾 = {'.', '?', '!'}
单词 = 字母 or 字母 单词
字母 = {'a'..'z', 'A'..'Z'}
空格 = ' '
(结尾为句子结尾。)

现在有一个字符串 $s$,问最少将 $s$ 拆分成多少个长度不超过 $n$ 的消息发出。

解法

思路

首先 $s$ 中的句子明显不可以调换顺序,所以只有相邻的句子能合并成一个消息。

具体地说,如果两个相邻的句子或消息 $a$ 和 $b$,若 $|a|+1+|b|\le n$,则可合并为 $a+b$。当然,合并后的消息也可以再次合并

注意:两个长度相加要再加 $1$,因为消息的定义之一为 消息 = 句子 空格 消息,空格也占一个长度。

所有句子的内容在本题中并不重要,只需知道它们的长度即可。

算法流程

  • 首先读入 $n,s$,处理出 $s$ 中每个句子的长度。
  • 将第一个句子的长度存入 vector 中。
  • 若还有句子,则尝试合并。
    • 如果两个相邻的句子或消息的长度相加再加 $1$ 小于等于 $n$,则合并。
  • 继续合并。

代码

有注释。

#include <iostream>
#include <string>
#include <vector>
using namespace std;

#define c s[i]
int main()
{
    int n;
    scanf("%d\n",&n);//一定要读入回车,否则 getline 会出错
    string s;
    getline(cin,s);//读入一整行
    int len=0,siz=s.size();//len:当前句子长度 siz:整个字符串长度
    vector<int> mes;
    for(int i=0;i<siz;i++)
    {
        if(c=='.'||c=='?'||c=='!')//如果句子结束
        {
            len++;
            if(len>n)//如果超限,输出不可能
            {
                puts("Impossible");
                return 0;
            }
            if(!mes.empty()&&mes.back()+len+1<=n)//能合并
            {
                mes.back()+=(len+1);//就合并
            }
            else
            {
                mes.push_back(len);//创建新消息
            }
            // printf("%d\n",len);
            i++;//跳过空格
            len=0;
        }
        else
        {
            len++;//否则长度加 1
        }
    }
    printf("%d\n",mes.size());//输出消息数量
    return 0;
}
posted @ 2023-07-19 16:13  Po7ed  阅读(3)  评论(0编辑  收藏  举报  来源