|
|||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
Разное.Задача "Быки и коровы"a) Пользователь загадывает число из 4 цифр, каждая из которых от 1
до 6, причем все цифры различны. Разработать алгоритм, который
угадывает число по следующим правилам: выводится число и
пользователь сообщает, сколько в нем "быков" и "коров", т.е.
сколько цифр стоят на своих местах и сколько цифр содержатся в
обоих числах, но совпадают лишь по значению. Например, пусть загадано число 1264, спрошено 1256. В этом случае 2 быка (1,2) и
одна корова (6)
Примечание : Спрошенное число должно удовлетворять правилам для загадываемого; компьютеру на ход дается 1 минута . Итак, 1-ое что приходит в голову играть по следующему правилу: называть первое попавшееся число, которое может быть задуманно, т.е. при сопоставлении любого ранее спрошенного числа с новым должно получится такое-же количество 'быков' и 'коров'. Число будем представлять в виде массива цифр.} const MaxSgn = 6; {Максимальное значение в числе} Итак, наша программа работает следующим образом: мы путем последовательного увеличения на 1 генерируем все возможные 6-значные числа, отбираем среди них те, в которых все цифры различные, и, наконец, те из них, которые удовлетворяют хранящимся в массиве Info ответам, задается пользователю в качестве вопроса. Возникает ряд резонных вопросов: сколько всего интересующих нас 4-значных цифр и какая их часть не содержит повторений. За сколько шагов может угадать ответ самый быстрый алгоритм и насколько хороша наша стратегия? Давайте попытаемся ответить на них. Итак сколько всего чисел? Пусть k цифр и m позиций. В первой позиции может стоять любая Из k цифр, что нам дает k вариантов. Во второй-также любая из k цифр, т.е. k2. И так далее m раз, т.е. всего km вариантов. Обобщим эту идею. Определение: размещение с n повторением из k элементов по m называется m-элементный массив натуральных чисел, каждое из которых не превосходит k. Утверждение: Число размещений с повторениями из k по m равно km. Доказательство проводим по индукции: Базис индукции: При m=1 у нас ровно k вариантов. Индуктивный переход: Пусть утверждение верно при m=n-1. Докажем, что оно верно при m=n. Зафиксируем число 1. Справа к этому числу припишем kn=1 размещений из k по n-1. Аналогично поступим с 1,2,3...k. Получим kn-1*k=kn вариантов. Таким образом, число 4-значных чисел с цифрами от 1 до 6 равно 64=1296. Теперь посмотрим, сколько из них не содержит повторяющихся цифр. Определения: размещением из k элементов по m называется m-элементный массив каждая компонента которого не превосходит k и среди них не встречаются одинаковые. Очевидно, что множество размещений не пусто лишь при m<=k. Число размещений из k по m принято обозначать A. Утверждение A=k*(k-1)*...(k-m+1)=k!/(k-m+1)! Доказательство проводим по индукции: Базис индукции: При m=1 у нас ровно k вариантов. Индуктивный переход: Пусть утверждение верно при m=n-1. Выберем любое из k!/(k-n+1)! размещений из k по n-1. Чисел, которые в нем не участвуют-(k-n+1). Приписывая их поочередно справа к выбранному размещению мы получим (k-n+1) вариантов. Перебирая все размещения: (k!/(k-n+1)!)*(k-n+1)=k!/(k-n)! Таким образом,число 4-значных чисел с цифрами от 1 до 6 без повторений равно A46=6*5*4*3=360, т.е. в 3 раза меньше, чем число вариантов, которые мы перебирали. Итак мы нашли один способ для оптимизации нашей программы: генерировать не все числа, а лишь те, которые не содержат повторяющихся цифр. Возьмем это на заметку, а сейчас попробуем оценить максимальное число шагов, за которое отгадывает лучший игрок. Вариантов ответа у нас: Пусть угадано 4 цифры. Среди них могут быть 2,1,0 "быков". Пусть угаданы 3 цифры. Среди них могут быть 3,2,1,0 "быков". И так далее: получаем 3+4+2+1=10 вариантов. Таким образом за каждый вопрос количество допустимых чисел уменьшается, если мы рассматриваем худший случай, не более чем в 10 раз. Число шагов, за которое угадывает лучший игрок, не менее чем [log10 360]+1=3 Ну а теперь попытаемся повысить эффективность работы программы. Как уже было отмечено выше, нам достаточно перебрать не 1096 комбинаций, а всего лишь 360. Это не отразится на быстроте угадывания, т.е. числе шагов, так как не изменим стратегии "первый попавшийся из подходящих", но уменьшит время обдумывания хода. Генерировать числа будем следующим образом: для начала выберем множество цифр, которое в него входит, ну а затем будем переставлять элементы этого множества между собой. Множество цифр удобно, для наших целей, представить в виде массива длины 4, элементы которого расположены в порядке возрастания. Будем генерировать эти массивы в лексикографическом порядке, т.е. сначала сравниваются первые цифры, если они равны - вторые, и так далее. То есть:
Значит, мы должны увеличить самую правую цифру, какую это возможно, и уменьшить затем те цифры, какие стоят за ней. Заметив, что номер цифры, которую нужно увеличивать, уменьшается на 1, а как только последний элемент массива можно будет увеличить, скачкообразно становится равной длине массива, приходим к следующему алгоритму: {n-число цифр} {A-массив который содержит текущие комбинации} Var Для генерирования всевозможных перестановок множества служит следующая идея: Пусть у нас сформированы всевозможные перестановки длины N-1. Вставляя оставшийся элемент в каждую перестановку во все возможные позиции, мы получим все комбинации длины n. Например, число 1 в перестановку 2 3 можно вставить следующими 3-мя способами:
Следует отметить, что получающиеся перестановки обладают приятным свойством: каждая перестановка получается из предыдущей путем обмена двух соседних элементов. Применяя эту идею рекурсивно, мы получим, например, следующую последовательность перестановок:
Для применения этого алгоритма в рекурсивной форме нам понадобится хранить всевозможные перестановки. Давайте попытаемся привести этот алгоритм к нерекурсивной форме. Для i-го элемента нам необходимо знать: Куда он сейчас движется - вправо или влево. Знать номер возможного из n-i+1 мест в перестановке длины n-i, которое он сейчас занимает. Мы приходим к следующему алгоритму: {B - массив элементов перестановки} Давайте попытаемся привести этот алгоритм к нерекурсивной форме. Для i-го элемента нам необходимо знать: Куда он сейчас движется-вправо или влево. Номер возможного из n-i+1 мест в перестановке длине n-i, которое он сейчас занимает. Мы проходим к следующему алгоритму: {В-массив элементов перестановки} Вверх по странице, к оглавлению и навигации.
|