Форум программистов, компьютерный форум CyberForum.ru

"Словесная игра" - C++

Восстановить пароль Регистрация
 
Рейтинг: Рейтинг темы: голосов - 8, средняя оценка - 4.63
R@nDoM
0 / 0 / 0
Регистрация: 13.04.2010
Сообщений: 4
13.04.2010, 16:29     "Словесная игра" #1
Собственно суть задачи :
В нашем варианте игры каждая буква имеет цену, и вы должны составить из букв одно и более слов, дающих максимальную суммарную стоимость. Даны цены букв , список русских слов и набор букв. Найдите в словаре или пары слов с наибольшей суммарной стоимостью , которые можно составить из заданного набора букв.
Цены букв во вложении.
Входные данные:
С клавиатуры вводим одну строку с маленькими русскими буквами(допустимые буквы- от "а" до "я").Строка содержит от трех до семи букв вкючительно , в произвольном порядке.
Файл словарь "words.txt" содержит не более 30 000(100 слов за глаза хватит). В конце этого файла находится строка с единственным символом "."(точка). Каждая из остальных строк содержит слово длиной от трех до семи маленьких латинских букв,включительно . Слова в файле упоряжочены по алфавиту.
Выходные данные:
В первую строку выходного файла output.txt ваша программа должна написать наибольшую возможную суммарную стоимость , а в следующих строках - перечислить все допустимые слова и, или пары слов из словаря words.txt с такой стоимостью. Каждое слово или пару выводите на отдельную строку.

P.S Наверное перестановки это главное в этой программе . Думаю там рекурсия.(Лаба так называется)
Миниатюры
"Словесная игра"  
Similar
Эксперт
41792 / 34177 / 6122
Регистрация: 12.04.2006
Сообщений: 57,940
13.04.2010, 16:29     "Словесная игра"
Посмотрите здесь:

C++ Консольная "графика", игра "Тетрис". Фигуры перестают прорисовываться на определенном этапе
C++ Карточная игра "Дурак" - Ошибка загрузки dll карт
Небольшой пример. Игра "змейка" - как в ней делают препятствия C++
C++ Игра "Жизнь"; Нужно, чтобы первое поколение задавалось оператором (с клавиатуры)
C++ Игра "Крестики нолики", почему не работает проверка окончания?
После регистрации реклама в сообщениях будет скрыта и будут доступны все возможности форума.
R@nDoM
0 / 0 / 0
Регистрация: 13.04.2010
Сообщений: 4
15.04.2010, 19:47  [ТС]     "Словесная игра" #2
Вот то что получилось у меня, проблема в том что функция перестановок у меня не правильная.
Нужно генерировать перестановки не только из того количества букв которые дали ,но и с меньшим кол-вом.
Поясню
пользователь ввел буквы а б в г д
программа будет генерировать перестановки со всеми буквами сразу.
а нужно чтобы генерерировало с
а б в г д
а б в г
а б в
в г д
и так далее...
как это реализовать не могу понять .
C++
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
#include <conio.h>
#include <stdio.h>
#include <iostream>
 
using namespace std;
 
 FILE *in,*word,*slova;
 int n1;
 char *a = new char[n1];
//---------------------------------------------------------------------------------------------------------------   
int scoreg(char *symbs)//функция которой мы передаем слово оно выдает кол-во очков
{
    int score=0,o=0;
    char y;
    y=symbs[0];
    while (y!=NULL)
    {   y=symbs[o];
        switch(y)
                {
                    case 'а':score=score+1;break;
                    case 'б':score=score+4;break;
                    case 'в':score=score+3;break;
                    case 'г':score=score+4;break;
                    case 'д':score=score+3;break;
                    case 'е':score=score+1;break;
                    case 'ж':score=score+5;break;
                    case 'з':score=score+5;break;
                    case 'и':score=score+1;break;
                    case 'й':score=score+5;break;
                    case 'к':score=score+1;break;
                    case 'л':score=score+1;break;
                    case 'м':score=score+1;break;
                    case 'н':score=score+1;break;
                    case 'о':score=score+2;break;
                    case 'п':score=score+2;break;
                    case 'р':score=score+2;break;
                    case 'с':score=score+2;break;
                    case 'т':score=score+2;break;
                    case 'у':score=score+5;break;
                    case 'ф':score=score+7;break;
                    case 'х':score=score+7;break;
                    case 'ц':score=score+8;break;
                    case 'ч':score=score+8;break;
                    case 'ш':score=score+9;break;
                    case 'щ':score=score+9;break;
                    case 'ъ':score=score+9;break;
                    case 'ы':score=score+9;break;
                    case 'ь':score=score+9;break;
                    case 'э':score=score+6;break;
                    case 'ю':score=score+6;break;
                    case 'я':score=score+5;break;
            }
                y=symbs[o];
                o++;
    }
    return score;
}
//----------------------------------------------------------------------------------------------------------------------------
void per(char *s,int n)//рекурсивная функция перестановок
 {
     int d;
     int i,j;
     if(n>1)
     {
        per(s,n-1);
        for(i=n-1;i>=1;i--)
        {   
            d=s[n-1];
            s[n-1]=s[i-1];
            s[i-1]=d;
            per(s,n-1);
            d=s[n-1];
            s[n-1]=s[i-1];
            s[i-1]=d;
        }
     
     }
     else
     {
         for(j=1;j<=n1;j++)
         {if (s[j-1]<=-81)fprintf(in,"%c",320+s[j-1]);
          if (s[j-1]>-81)fprintf(in,"%c",272+s[j-1]);
         }
         fprintf(in,"\n");
     }
 }
//----------------------------------------------------------------------------
int main(void)// Главная функция;
{
setlocale (LC_ALL,"RUS");
cout<<"Введите кол-во букв: ";
cin>>n1;
cout<<"Введите буквы: ";
for(int i=0;i<n1;i++)
cin>>a[i];  
in=fopen("combinations.txt","w");
per(a,n1);
fclose(in);
//----------------------------------------------------------------------------------
in=fopen("combinations.txt","r");
slova=fopen("slova.txt","w");
//-------------------------------------------------------------------------------
char *str,*str1,*str2;
int g;
str=new char [50];
str1=new char [50];
str2=new char [50];
//-----------------------------------------------------------------------------
while(!feof(in))//проверяем все перестановки на "слово" и пишем в файл slova.txt
{
   fscanf(in,"%s",str1);
   word=fopen("word.txt","r");
   fscanf(word,"%s",str2);
   while(!feof(word))
    {
        if(strcmp(str1,str2)==0) {fprintf(slova,"%s",str1);fprintf(slova,"\n");}
         fscanf(word,"%s",str2);
     
   }
fclose(word); 
}
fclose(slova);
slova=fopen("slova.txt","r");
//----------------------------------------------------------------------------
while (!feof(slova))//считаем стоимость слов.
{fscanf(slova,"%s",str);
cout<<str<<"\n";
g=scoreg(str);
cout<<g<<"\n";
}
//-----------------------------------------------------------------------------
//закрытие файлов
fclose(slova);
fclose(in);
}
valeriikozlov
Эксперт C++
 Аватар для valeriikozlov
4660 / 2486 / 321
Регистрация: 18.08.2009
Сообщений: 4,550
18.04.2010, 19:37     "Словесная игра" #3
Цитата Сообщение от R@nDoM Посмотреть сообщение
Нужно генерировать перестановки не только из того количества букв которые дали ,но и с меньшим кол-вом.
А может все проще сделать. Берем первое слово в словаре. Если в этом слове есть буквы которые мы не вводили, то переходим сразу к следующему слову в словаре. Если все буквы данного слова совпали с введенными и их кол-во равно введенным, то вычисляем стоимость и сравниваем ее с текущей (изначально текущая стоимость, как Вы догадались равна 0). Если остались еще свободные буквы (из введенных), то продолжаем поиск второго слова состоящего только из оставшихся букв (продолжаем поиск не с начала словаря а со следующего слова до конца словаря).
По-моему так намного проще.
silent_1991
Эксперт C++
4938 / 3014 / 149
Регистрация: 11.11.2009
Сообщений: 7,024
Завершенные тесты: 1
18.04.2010, 21:08     "Словесная игра" #4
Пара вопросов:
1. Мы вводим от 3 до 7 букв, но обязательно ли слово из словаря тоже должно быть длиной от 3 до 7 букв соответственно? Т.е. могут ли введённые буквы в результирующем слове (паре слов) повторяться?
2. Все слова в словаре идут поодиночке? Отдельных пар в словаре нету, т.е. нашу пару мы можем составить только из пары записей в словаре?
R@nDoM
0 / 0 / 0
Регистрация: 13.04.2010
Сообщений: 4
19.04.2010, 03:36  [ТС]     "Словесная игра" #5
Цитата Сообщение от silent_1991 Посмотреть сообщение
1. Мы вводим от 3 до 7 букв, но обязательно ли слово из словаря тоже должно быть длиной от 3 до 7 букв соответственно? Т.е. могут ли введённые буквы в результирующем слове (паре слов) повторяться?
Буквы не повторяются
Цитата Сообщение от silent_1991 Посмотреть сообщение
Все слова в словаре идут поодиночке? Отдельных пар в словаре нету, т.е. нашу пару мы можем составить только из пары записей в словаре?
Да
Цитата Сообщение от valeriikozlov Посмотреть сообщение
А может все проще сделать. Берем первое слово в словаре. Если в этом слове есть буквы которые мы не вводили, то переходим сразу к следующему слову в словаре. Если все буквы данного слова совпали с введенными и их кол-во равно введенным, то вычисляем стоимость и сравниваем ее с текущей (изначально текущая стоимость, как Вы догадались равна 0). Если остались еще свободные буквы (из введенных), то продолжаем поиск второго слова состоящего только из оставшихся букв (продолжаем поиск не с начала словаря а со следующего слова до конца словаря).
По-моему так намного проще.
Может быть и проще , только где тут рекурсия?
valeriikozlov
Эксперт C++
 Аватар для valeriikozlov
4660 / 2486 / 321
Регистрация: 18.08.2009
Сообщений: 4,550
19.04.2010, 05:54     "Словесная игра" #6
Цитата Сообщение от R@nDoM Посмотреть сообщение
Может быть и проще , только где тут рекурсия?
Ну например рекурсию можно использовать так (я в качестве примера накидаю в общих чертах рек. функцию поиска слова (двух слов) с максимальной стоимостью):
C++
1
2
3
4
5
int rec_func(int temp_i, int col_w, int temp_sum, char *mas)// здесь в качестве параметров передаются: temp_i - текущий индекс слова в словаре, col_w - количество уже задействованных слов (их может не более 2-х), temp_sum - текущая сумма слова (двух слов), *mas - массив свободных букв (в принципе вместо него можно использовать и массив int-вских значений, для указания индексов свободных букв, которые ввели).
Сама функция должна выполнять следующее:
- проверку на то что набранных слов не более 2-х и проверку что не достигли конца словаря;
- проверку очередного слова из словаря для набора введенных символов;
- если очередное слово подходит и буквы еще остались, то вызываем снова нашу rec_func().
silent_1991
Эксперт C++
4938 / 3014 / 149
Регистрация: 11.11.2009
Сообщений: 7,024
Завершенные тесты: 1
19.04.2010, 11:59     "Словесная игра" #7
Я бы дела так. Ищем все комбинации введённых букв (не обязательно всего набора) (можно буквы пронумеровать индексами от 1 до 3 (4, 5, 6, 7, в зависимости от ввода) и искать комбинации цифр 123, либо 1234, 12345, 123456, 1234567, а потом для каждого найденного набора вместо цифры подставлять нужную букву), далее для каждого найденного набора букв искать все слова в словаре, совпадающие с найденным наборами. Заносить эти слова в, например, массив строк. Далее мы просто считаем вЕсы всех найденных слов или их пар (пару составляем так: берём первое слово, далее подставляем к нему второе, третье, ... , n-е, затем берём второе слово, к нему подставляем третье, ..., n-е и т.д, но это и так понятно))) ), находим максимальный, а затем снова просматриваем массив строк, составляя слова (или пары) с найденным весом. Выводим переменную max (максимальный вес) и отредактированный массив строк, содержащий только слова (или пары) с таким весом.
Скорее всего рекурсия будет в функции, ищущей наборы букв.

Добавлено через 50 минут
Так, вся фишка сейчас в том, чтобы написать функцию, ищущую все эти возможные перестановки... Думаю, нужно написать сначала код, ищущий перестановку N чисел, и затем для каждой найденной перестановки рекурсивно применять его для N-1 чисел...

Добавлено через 32 минуты
Так, чтобы перебрать все возможные варианты для N цифр, мы просто берём последнюю цифру числа и "тянем" её через всё число, пока она не займёт первую позицию. Затем в получившемся числе берём последнюю цифру и опять "тянем" её вдоль числа до первой позиции и т.д. Продолжаем, пока последнее число не совпадёт с исходным. Пример для числа 123 (для нашей задачи: например, пользователь ввёл "адф". Нумеруем а = 1, д = 2, ф = 3, ищем комбинацию для 123, подставляем вместо цифр соответствующие буквы и ищем получившееся слово в словаре)
Пример: пользователь ввёл отк. Нумеруем: о = 1, т = 2, к = 3. Ищем комбинации
123 132 312
321 231
213 123 (совпало с начальным -> отбрасываем последний результат).
Получили ряд
123 132 312 321 231 213 он соответствует словам
отк окт кот кто тко ток
Скорее всего найденные в словаре слова будут: кот, кто, ток

Осталось подумать, пренебречь ли ресурсами и тупо ко всем найденным перестановкам рекурсивно применять алогритм для меньшего числа цифр (тогда будут повторяться некоторые наборы, соответственно будет происходить повторная процедура поиска), или же пренебречь памятью и хранить все найденные перестановки в массиве строк, исключая повторения, а уже после нахождения ВСЕХ возможных перестановок включать процедуру поиска...

Добавлено через 18 секунд
И я склоняюсь ко второму варианту.
valeriikozlov
Эксперт C++
 Аватар для valeriikozlov
4660 / 2486 / 321
Регистрация: 18.08.2009
Сообщений: 4,550
19.04.2010, 19:19     "Словесная игра" #8
Цитата Сообщение от silent_1991 Посмотреть сообщение
Так, чтобы перебрать все возможные варианты для N цифр, мы просто берём последнюю цифру числа и "тянем" её через всё число, пока она не займёт первую позицию.
Для примера в котором всего три буквы этот вариант пройдет.
silent_1991, попробуйте так: начальное число - 1234. Комбинацию 1432 Вы таким способом не получите...
silent_1991
Эксперт C++
4938 / 3014 / 149
Регистрация: 11.11.2009
Сообщений: 7,024
Завершенные тесты: 1
20.04.2010, 16:28     "Словесная игра" #9
valeriikozlov,
Хи, и правда... А я вроде всё проверил, обрадовался))) Есть какой-то другой способ? Алгоритмический?

Добавлено через 19 минут
А если так: делаем инкремент для чисел с 1 по N, а затем удаляем из полученного набора все вхождения чисел, в которых на каком-либо разряде стоит цифра больше N (или же 0)? Единственная загвоздка: для 7 введённых букв придётся хранить 7654321 чисел...

Добавлено через 4 минуты
Тогда можно делать, как я предлагал раньше, ищем следующую комбинацию, проверяем её на правильность (ищем разряды, большие N или нулевые), и сразу выполняем процедуру поиска. Ну или можно искать комбинацию, проверять её на правильность, а уже потом записывать в наш список комбинаций... Правда так всё равно будет куча операций прибавления единицы, но зато просто и зходу найдутся все возможные варианты перестановок не только с данным количеством разрядов, но и с меньшим... И никакой рекурсии)))

Добавлено через 14 минут
Вот, вроде придумал алгоритм...
Берём выборку для одной цифры. Скажем мы ввели три буквы. получили число 123. Возьмём выборку:

1
2
3

Далее для каждой найденной выборки добавляем один младший разряд и в него записываем каждую недостающую цифру. Взяли 1. Недостающие цифры - 2 и 3. получили

12
13

Так же поступаем с остальными. Недостающий цифры для 2 - 1 и 3, для 3 - 1 и 2. Распишем:

21
23

31
32

Далее в каждой найденной выборке предыдущего шага (т.е. из двух, в данном случае, цифр) добавляем ещё разряд и в него записываем недостающие цифры для каждой пары (например для 23 недостающая цифра - 1, для 31 - 2 и т.д.). Получаем:

123
132
213
231
312
321

Всё, перебрали все варианты - выходим (как критерий можно использовать то, что изначальное расположение цифр 123, а конечно всегда будет перевёрнутым - 321. Только что ради эксперимента расписал для четырёх цифр - получилось 64 комбинации). Думаю, это надо рекурсивно реализовать...

Добавлено через 42 минуты
Кстати, для 7 цифр число размещений будет равно 13699... Нехило, а?)))

Добавлено через 16 часов 32 минуты
Так, научился считать все перестановки N цифр... Теперь надо придумать, как считать перестановки для N-1 цифр... Есть идея у всех перестановок предыдущего ((K-1)-го) шага отсекать последний разряд и для каждого получившегося набора рекурсивно запускать функцию перестановки. Для каждой найденной перестановки проверять, нет ли уже такой перестановки в нашем массиве перестановок, если нет - записывать туда найденный набор, если есть - искать следующую перестановку...
Правда поиск уже для 5 разрядов визуально заметен, а для 7 занимает (на глаз) 2,5 - 3 секунды...
silent_1991
Эксперт C++
4938 / 3014 / 149
Регистрация: 11.11.2009
Сообщений: 7,024
Завершенные тесты: 1
23.04.2010, 21:44     "Словесная игра" #10
Жаль, что тема сдохла... А у меня появился код формирования всех сочетаний без повторенийдля чисел от 1 до N...

C
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
#include <stdio.h>
#include <string.h>
 
#define maxn 8
#define raz 32
#define beg 1
 
unsigned int set[maxn], razr[maxn];
 
int add_set(unsigned int s[], int n)
{
    if (n / raz < maxn)
    {
        s[n / raz] |= 0x01 << (n % raz);
    }
    else
    {
        return -1;
    }
    
    return 0;
}
 
int del_set(unsigned int s[], int n)
{
    if (n / raz < maxn)
    {
        s[n / raz] &= ~(0x01 << (n % raz));
    }
    else
    {
        return -1;
    }
    
    return 0;
}
 
int pr_set(unsigned int s[], int n)
{
    if (n / raz < maxn)
    {
        if ((s[n / raz] >> (n % raz)) & 0x01)
        {
            return 1;
        }
        else
        {
            return 0;
        }
    }
    else
    {
        return -1;
    }
}
 
void rast(int n, int yr, int n_yr)
{
    int i;
    
    if (n_yr == yr)
    {
        for (i = 0; i < n_yr; i++)
        {
            printf("%d", razr[i]);
        }
        
        printf("\n");
        del_set(set, razr[yr - 1]);
        
        return;
    }
    
    for (i = razr[yr] + 1; i < (beg + n); i++)
    {
        if (!pr_set(set, i))
        {
            del_set(set, razr[yr]);
            add_set(set, i);
            razr[yr] = i;
            rast(n, yr + 1, n_yr);
        }
    }
    
    del_set(set, razr[yr]);
    razr[yr] = beg - 1;
}
 
int main()
{
    int n;
    int i;
    
    printf("Введите количество разрядов: ");
    scanf("%d", &n);
    
    for (i = 0; i < maxn; i++)
    {
        razr[i] = beg - 1;
    }
    
    for (i = 1; i <= n; i++)
    {
        rast(n,0,i);
    }
    
    getch();
    return 0;
}
R@nDoM
0 / 0 / 0
Регистрация: 13.04.2010
Сообщений: 4
24.04.2010, 04:48  [ТС]     "Словесная игра" #11
а нужны буквы.
MoreAnswers
Эксперт
37091 / 29110 / 5898
Регистрация: 17.06.2006
Сообщений: 43,301
24.04.2010, 06:11     "Словесная игра"
Еще ссылки по теме:

Игра "Чёт-Нечет" на поле NxN, перевести с Делфи на С++ C++
C++ Текстовая игра "Кто хочет стать миллионером?" с использованием классов
C++ Игра "Однорукий бандит". Кольцевая очередь. Двусвязный список

Искать еще темы с ответами

Или воспользуйтесь поиском по форуму:
silent_1991
Эксперт C++
4938 / 3014 / 149
Регистрация: 11.11.2009
Сообщений: 7,024
Завершенные тесты: 1
24.04.2010, 06:11     "Словесная игра" #12
И? Нумеруем буквы...
abc
123
Делаем все перестановки
1
2
3
12
13
23
21
31
32
123
132
213
231
312
321

Получаем

a
b
c
ab
ac
bc
ba
ca
cb
abc
acb
bac
bca
cab
cba

И теперь с этим набором работаем.
Yandex
Объявления
24.04.2010, 06:11     "Словесная игра"
Ответ Создать тему
Опции темы

Текущее время: 17:01. Часовой пояс GMT +3.
КиберФорум - форум программистов, компьютерный форум, программирование
Powered by vBulletin® Version 3.8.9
Copyright ©2000 - 2016, vBulletin Solutions, Inc.
Рейтинг@Mail.ru