Распределить слова по группам и сгенерировать текст C++

  • Суть программы:
    • Пользователь задаёт алфавит языка (вводит несколько букв) и максимальную длину слова (вводит число);
    • Программа генерирует все возможные слова из этих букв (не обязательно существующие);
    • Все слова рандомно распределяются на 3 группы;
    • Пользователь задаёт количество предложений для текста;
    • Программа составляет текст из предложений по типу: 1 рандомное слово из 1-ой группы + 1 рандомное слово из 2-ой группы + 1 рандомное слово из 3 группы. (То есть в предложении 3 слова, кол-во предложений задает пользователь);
    • Вывести этот текст в отдельный файл.

Не могу сделать нормально 3-5 пункт. Наверное, нужно изначально слова в массив забивать, но не знаю как. Или есть еще какой способ? Подскажите, пожалуйста.

#include <iostream> 
#include <stdio.h>
#include <windows.h>
#include <string>
#include <time.h>
using namespace std;

void vocabulary(string s, string h, string* vocab, string* skaz, string* podl, string* dop, int n)
{    
    string k;
    for (size_t i = 0; i < h.length(); i++)
    {
        if (s.length() == n)
        { break; }
        k = h;
        vocabulary(s + h[i], h, vocab, skaz, podl, dop, n);
    }
    *vocab += s + '\n';

    int i = rand() % 3;    
    if (i == 0) {*skaz += s + ' '; }
    if (i == 1) {*podl += s + ' '; }
    if (i == 2) {*dop += s + ' '; }   
}

int main()
{
    setlocale(0, "");
    srand(time(0));

    string alphabet, vocab, skaz, podl, dop, text;
    int length, n;

    cout << "Задайте алфавит языка:\t";
    cin >> alphabet;

    cout << "Задайте максимальную длину слова:\t";
    cin >> length;

    cout << "Словарь языка:\n";
    vocabulary("", alphabet, &vocab, &skaz, &podl, &dop, length);
    cout << vocab << "---------------------------------\n";    

    cout << skaz << endl;
    cout << podl << endl;
    cout << dop << endl;

    cout << "Введите количество предложений для текста:\t";
    cin >> n;    

    system("pause");
    return 0;
}


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

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

Вот Вам вариант моего решения:

Алгоритм:

1) Берем строку символов и подготавливаем ее (делаем уникальной и все low и без цифр и пробелов) ну или введите свои символы и отработайте аналогично.

2) Генерируем все комбинации по пример f(ab,2) -> aa ab ba bb и тд. Учтите,что это надо повторить от 1 буквы до макс длинны слова от 1 буквы до максимума чтобы получить все комбинации разной длинны. + данные будут генерироваться без "схожих" (aac caa) которые при пермутации будут давать одинаковые данные.

3) Пермутим строку и прогоняем ее через std::set чтобы все было юникально

4) Далее чпросто рандомно перемешиваем конетйнер всех слов и дробим его на n частей (2 параметр в GenDicts) части

5) генерим те же n чисел числа и готовим новую строку по индексам этих рандомов

ПРОФИТ

Вот код:

#include <string>
#include <iostream>
#include <vector>
#include <set>
#include <random>
#include <algorithm>
#include <functional>
#include <iterator>


std::string PrepareStr(std::string line) {

    std::for_each(std::begin(line), std::end(line), [](char& c){ if (std::isupper(c)) {c = std::tolower(c);}});

    if (!std::is_sorted(std::begin(line), std::end(line))) {
        std::sort(std::begin(line), std::end(line));
    }

    line.erase(std::unique(std::begin(line), std::end(line)), std::end(line));
    line.erase(std::remove_if(std::begin(line), std::end(line), [](char c){ return std::isdigit(c) || std::isspace(c) ; }), std::end(line));

    return line;
}


void CombinationRepetitionUtil(std::vector<std::string>& ret, std::vector<int> chosen, std::string& line, 
                    std::size_t index, std::size_t r, int start, int end) { 

    if (index == r) { 
        std::string tmp;
        for (std::size_t i = 0; i < r; i++) {
            tmp += line[static_cast<std::size_t>(chosen.at(i))];
        }
        ret.push_back(tmp);
        return;
    }

    for (int i = start; i <= end; i++) { 
        chosen[index] = i; 
        CombinationRepetitionUtil(ret, chosen, line, index + 1, 
                                               r, i, end); 
    } 
    return; 
} 


std::vector<std::string> CombinationRepetition(std::string line, int n, std::size_t r) { 

    std::vector<int> chosen(static_cast<std::size_t>(r + 1));
    std::vector<std::string> ret;

    CombinationRepetitionUtil(ret, chosen, line, 0, r, 0, n-1);

    return ret;
}


std::vector<std::string> GenAllWorlds(std::vector<std::string> v) {

    std::set<std::string> s;

    for (auto line : v) {
        do {
            s.insert(line);
        } while (std::next_permutation(std::begin(line), std::end(line)));
    }

    return {std::begin(s), std::end(s)};
}


uint64_t GenRandUInt(std::size_t  low_bound, std::size_t  hight_bound) {

    static std::random_device r_dev{};
    static std::mt19937_64 mt_engine(r_dev());
    static std::uniform_int_distribution<> u_int_d(static_cast<int32_t>(low_bound), 
                                            static_cast<int32_t>(hight_bound));
    static auto PRNG{std::bind(u_int_d, mt_engine)};

    return static_cast<uint64_t>(PRNG());
}


std::vector<std::vector<std::string>> GenDicts(std::vector<std::string> m, std::size_t dict_count) {

    std::vector<std::vector<std::string>> ret(dict_count);

    auto randomer = [](int N){  static std::random_device r_dev{};
                                        std::mt19937_64 generator(r_dev());
                                            std::uniform_int_distribution<> uid(0, N-1);
                                            return uid(generator);};

    std::random_shuffle(std::begin(m), std::end(m), randomer);

    for (size_t i{0}; i < dict_count; ++i) {
        size_t k{m.size() / dict_count};
        size_t kk{m.size() % dict_count};

        auto b_it = std::begin(m);
        if (i != dict_count - 1) {
            ret[static_cast<std::size_t>(i)].resize(k);
            std::copy(std::begin(m) + i * k,
                      std::begin(m) + (i + 1) * k,
                      std::begin(ret[i]));
        } else {
            ret[static_cast<std::size_t>(i)].resize(k + kk);
            std::copy(std::begin(m) + i * k,
                      std::begin(m) + (i + 1) * k + kk,
                      std::begin(ret[i]));
        }

    }

    return ret;
}

std::string Genline(std::vector<std::vector<std::string>> v) {

    std::string ret;
    for (int i{0}; i < v.size(); ++i) {
        ret += v[1][GenRandUInt(0, v[1].size() - 1)];
        if (i != v.size() - 1) {
            ret += " ";
        }
    }

    return ret;
}


int main() {

    std::string alphabet{"abc fa324 X h dfah2443d eee"};
    alphabet = PrepareStr(alphabet);
    std::cout << "line is : " << alphabet << std::endl;

    std::size_t lenth_size{2};

    std::vector<std::string> mm{};

    for (int i = 1; i <= lenth_size; ++i) {
        auto comb{CombinationRepetition(alphabet, static_cast<int>(alphabet.length()), i)};
        auto m{GenAllWorlds(comb)};
        mm.insert(std::end(mm), std::make_move_iterator(std::begin(m)),std::make_move_iterator(std::end(m)));
    }

    std::cout << "mm size = " << mm.size() << std::endl;

    auto three_dict{GenDicts(mm, 4)};

    for (const auto cnt : three_dict) {
        std::cout << cnt.size() << std::endl;
    }

    std::cout << Genline(three_dict) << std::endl;

    return 0; 
}
→ Ссылка