Задача Контрольная по ударениям

Контрольная по ударениям Учительница задала Пете домашнее задание — в заданном тексте расставить ударения в словах, после чего поручила Васе проверить это домашнее задание. Вася очень плохо знаком с данной темой, поэтому он нашел словарь, в котором указано, как ставятся ударения в словах. К сожалению, в этом словаре присутствуют не все слова. Вася решил, что в словах, которых нет в словаре, он будет считать, что Петя поставил ударения правильно, если в этом слове Петей поставлено ровно одно ударение.

Оказалось, что в некоторых словах ударение может быть поставлено больше чем одним способом. Вася решил, что в этом случае если то, как Петя поставил ударение, соответствует одному из приведённых в словаре вариантов, он будет засчитывать это как правильную расстановку ударения, а если не соответствует, то как ошибку.

Вам дан словарь, которым пользовался Вася, и домашнее задание, сданное Петей. Ваша задача — определить количество ошибок, которое в этом задании насчитает Вася.

Входные данные

Вводится сначала число N — количество слов в словаре (0≤N≤20000).

Далее идёт N строк со словами из словаря. Каждое слово состоит не более чем из 30 символов. Все слова состоят из маленьких и заглавных латинских букв. В каждом слове заглавная ровно одна буква — та, на которую падает ударение. Слова в словаре расположены в алфавитном порядке. Если есть несколько возможностей расстановки ударения в одном и том же слове, то эти варианты в словаре идут в произвольном порядке.

Далее идёт упражнение, выполненное Петей. Упражнение представляет собой строку текста, суммарным объёмом не более 300000 символов. Строка состоит из слов, которые разделяются между собой ровно одним пробелом. Длина каждого слова не превышает 30 символов. Все слова состоят из маленьких и заглавных латинских букв (заглавными обозначены те буквы, над которыми Петя поставил ударение). Петя мог по ошибке в каком-то слове поставить более одного ударения или не поставить ударения вовсе.

Выходные данные

Выведите количество ошибок в Петином тексте, которые найдёт Вася.

Примечания к примерам тестов

В слове cannot, согласно словарю возможно два варианта расстановки ударения. Эти варианты в словаре могут быть перечислены в любом порядке (т.е. как сначала cAnnot, а потом cannOt, так и наоборот). Две ошибки, совершённые Петей, — это слова be (ударение вообще не поставлено) и found (ударения нет). Слово thE отсутствует в словаре, но поскольку в нём Петя поставил ровно одно ударение, признаётся верным.

Неверно расставлены ударения во всех словах, кроме The (оно отсутствует в словаре, в нём поставлено ровно одно ударение). В остальных словах либо ударные все буквы (в слове PAGE), либо не поставлено ни одного ударения.

Ввод

4
cAnnot
cannOt
fOund
pAge
thE pAge cAnnot be found

Вывод

2

Ввод

4
cAnnot
cannOt
fOund
pAge
The PAGE cannot be found

Вывод

4

Мой код:

#include <iostream>
#include <algorithm>
#include <string>
#include <set>

using namespace std;

int main() {
    set<string> voc;
    set<string> voc_;
    string word, word_lower;
    size_t n_word;
    size_t errors = 0;
    size_t count;
    cin >> n_word;

    while (--n_word && cin >> word) {
        voc.insert(word);
        transform(word.begin(), word.end(), word.begin(), ::tolower);
        voc_.insert(word);
    }

    while (cin >> word) {
        if (voc.find(word) == voc.end()) {
            word_lower.clear();
            transform(word.begin(), word.end(), back_inserter(word_lower), ::tolower);
            if (voc_.find(word_lower) != voc_.end()) {
                ++errors;
            } else {
                count = 0;
                for (auto simvol : word) {
                    if (isupper(simvol)) {
                        ++count;
                    }
                    if (count > 1) {
                        ++errors;
                        break;
                    }
                }
                if (count == 0) {
                    ++errors;
                }
            }
        }
    }

    cout << errors;
}

Помогите пожалуйста разобраться, что не так. Нет вывода, постоянный ввод, хотя если вначале ввожу не число, то сразу выдаёт 0


Ответы (1 шт):

Автор решения: needKVAS

std::cin при приведении к bool возвращает true, если не поднято никаких флагов ошибок. При этом если форматированный ввод >> не удался ставится флаг ошибки failbit. Таким образом, если вводится не число, все дальнейшие вызовы std::cin возвращают false и программа не попадает ни в один из циклов. Чтобы сбросить флаг ошибки можно использовать:

if (std::cin.fail()) { //Если произошла ошибка
    std::cin.clear(); //Сбрасываем флаг ошибки
    std::cin.ignore(std::numeric_limits<std::streamsize>::max(), '\n'); //Очищаем буфер
}

Бесконечный же ввод происходит из-за цикла while (cin >> word), из которого вы бесконечно выбираете слова. Используйте ctrl+z (Windows) или ctrl+d (Unix) для завершения ввода либо, например, воспользуйтесь std::getline для получения строки. Возможно, в этом случае проще всего будет проверять следующий символ в std::cin на перевод строки:

while (cin >> word) {
    //Делаем расчёты
    //...
    
    //Проверяем следующий символ в cin на перевод строки
    if (std::cin.peek()=='\n') {
        break;
    }
}

Через std::getline с минимальными изменениями кода можно сделать, например, так:

std::string line;
std::cin.ignore(std::numeric_limits<std::streamsize>::max(), '\n'); //Чистим буфер
std::getline(std::cin, line); //Считываем строку
std::istringstream stream(line); //Создаём строковый поток
while (stream >> word) { //Читаем из него слова
    //Делаем расчёты
    //...
}

А ещё --n_word в первом цикле лучше заменить на n_word--. В первом случае вы сначала уменьшаете счётчик слов на 1, а потом проверяете его для условия. Из-за этого вы будете вводить на одно слово меньше.

→ Ссылка