Ханойские башни
История и суть задачи "Ханойские башни", построение ее математической модели в виде рекуррентного соотношения. Решение задачи с помощью рекурсии и кода Грея, ее связь с теорией графов. Анализ временных затрат. Различные головоломки с измененным условием.
Рубрика | Программирование, компьютеры и кибернетика |
Вид | курсовая работа |
Язык | русский |
Дата добавления | 06.08.2013 |
Размер файла | 1021,6 K |
Отправить свою хорошую работу в базу знаний просто. Используйте форму, расположенную ниже
Студенты, аспиранты, молодые ученые, использующие базу знаний в своей учебе и работе, будут вам очень благодарны.
Размещено на http://www.allbest.ru/
Министерство образования Российской Федерации
ФГБОУ ВПО Кубанский государственный технологический университет
(КубГТУ)
Кафедра Вычислительной техники и АСУ
Факультет Компьютерных технологий и автоматизированных систем
КУРСОВАЯ РАБОТА
По дисциплине Алгоритмы и структуры данных
На тему: Ханойские башни
Выполнил: студент группы 11-КБ-ПР1
Сериков Александр Юрьевич
Руководитель работы: Е.А.Симоненко
Члены комиссии:
Е.А.Симоненко
В.А. Мурлина
А.Г. Волик
Краснодар 2012
Реферат
Пояснительная записка курсовой работы 37 с., 12 рис., 0 табл., 5 ист., 6 прил.
Visual Studio 2010, С#, Рекурсия, КОД ГРЕЯ, Ханойские башни, графы.
В данной курсовой работе рассмотрена реализация рекурсивного алгоритма «Ханойские башни».
Основными моментами проведённого исследования были: изучение рекурсивного алгоритма для решения поставленной задачи, применение кода Грея для решения задачи о Ханойских башнях, методы работы с языком программирования С#, а так же связь этой задачи с теорией графов.
Проделанная работа дала нам представление об алгоритме действия рекурсии на примере задачи о Ханойских башнях, что помогло в создании программы.
Содержание
Введение
1. История задачи «Ханойские башни»
2. Суть задачи
3. Построение модели
4. Решение с помощью рекурсии
5. Сложность и затраты времени
6. Связь задачи «Ханойские башни» с теорией графов
7. Применение кода Грея для решения
8. Различные задачи с измененным условием
Заключение
Список используемой литературы
Приложения
Введение
Ханойские башни - это игра, в которой используются три штыря и набор дисков. Все диски различаются диаметром и нанизываются на штыри через отверстие в центре каждого диска. Первоначально все диски находятся на левом штыре.
Цель игры состоит в том, чтобы переместить все диски на центральный штырь. Правый штырь можно использовать как «запасной» для временного размещения дисков. При каждом перемещении диска с одного штыря на другой должны соблюдаться два ограничения: перемещать можно только самый верхний диск на штыре, и, кроме того, нельзя ставить диск на другой диск меньшего размера.
В данной курсовой работе будет рассмотрен способ решения поставленной задачи «Ханойские башни», связь этой задачи с теорией графов. Так же будут рассмотрены рекурсия, на примере данной задачи и код Грея.
1. История задачи «Ханойские башни»
Эту известную игру придумал французский математик Эдуард Люка, в 1883 году её продавали как забавную игрушку. Первоначально она называлась «Профессор Клаус из Колледжа Ли-Су-Стьян» но вскоре обнаружилось, что таинственный профессор из несуществующего колледжа - не более чем анаграмма фамилии изобретателя игры - профессора Люка из колледжа Сен-Луи.
Но история этой задачи уходит довольно глубже. Легенда гласит, что в Великом храме города Бенарас, под собором, отмечающим середину мира, находится бронзовый диск, на котором укреплены 3 алмазных стержня, высотой в один локоть и толщиной с пчелу. Давным-давно, в самом начале времён, монахи этого монастыря провинились перед богом Брахмой. Разгневанный, Брахма воздвиг три высоких стержня и на один из них возложил 64 диска. Брахма поместил на один из стержней 64 диска из чистого золота, причем так, что каждый меньший диск лежит на большем.
Как только все 64 диска будут переложены со стержня, на который Брахма сложил их при создании мира, на другой стержень, башня вместе с храмом обратятся в пыль и под громовые раскаты погибнет мир.
Количество перекладываний в зависимости от количества колец вычисляется по формуле .
Число перемещений дисков, которые должны совершить монахи, равно 18 446 744 073 709 551 615. Если бы монахи, работая день и ночь, делали каждую секунду одно перемещение диска, их работа продолжалась бы 584 миллиарда лет.
В информатике задачи, основанные на легенде о Ханойской башне, часто рассматривают в качестве примера использования рекурсивных алгоритмов и преобразования их к не рекурсивным.
2. Суть задачи
Ханойская башня является одной из популярных головоломок XIX века. Даны три стержня из N дисков разного диаметра, которые надеты на стержень (1) в порядке убывания диаметра (Рис. 1).
1 2 3
Рис. 1 (стержни и диски)
Надо переместить N дисков за наименьшее число шагов на стержень (3), так чтобы они остались в таком же порядке. При этом требуется соблюдать правила:
· На каждом шаге ровно один диск перемещается с одного диска на другой;
· Диск большего диаметра нельзя помещать на диск меньшего диаметра;
· Стержень (2) можно использовать как промежуточный.
3. Построение модели
Математической моделью данной задачи является рекуррентное соотношение.
Рекуррентное соотношение - это соотношение, которое выражает значение функции с помощью других значений, вычисленных для меньших аргументов. Исходя из данного определения, следует, что для каждой рекуррентной функции нужно задавать хотя бы одно значение.
4. Решение с помощью рекурсии
Многим из тех людей, которые играют в эту игру, практически никогда не удается обнаружить весьма простую стратегию, позволяющую успешно играть в Ханойские башни с тремя штырями и N дисками. Чтобы не утомлять вас поисками решения этой задачи, мы откроем его:
* Граничное условие выполняется в случае, когда на исходном (левом) штыре нет дисков.
* Переместить N-1 дисков с исходного штыря на запасной (правый) штырь, используя итоговый штырь как запасной; отметим, что это перемещение осуществляется рекурсивно.
* Переместить один диск с исходного штыря на итоговый штырь. В этом месте наша программа будет выдавать сообщение об этом перемещении.
* Наконец, переместить N-1 дисков с запасного на итоговый, используя исходный штырь в качестве запасного.
Начнем с самого маленького кольца и переложим его на любую отметку. В дальнейшем это кольцо нужно перемещать в том же направлении, что и при первом перекладывании. Затем произведем единственно возможное перемещение оставшихся колец, после чего снова переложим самое маленькое кольцо и т. д. (Интересно заметить, что, перенумеровав «кольца» по порядку, мы добьёмся неожиданного эффекта: четные кольца будут перемещаться из одной вершины треугольника в другую в одном направлении, а нечётные - в противоположном направлении.)
Задача о ханойских башнях - это классический пример применения рекурсии для описания эффективного алгоритма.
В программировании рекурсия - вызов функции (процедуры) из неё же самой, непосредственно (простая рекурсия) или через другие функции (сложная или косвенная рекурсия), например, функция вызывает функцию , а функция - функцию . Количество вложенных вызовов функции или процедуры называется глубиной рекурсии.
Преимущество рекурсивного определения объекта заключается в том, что такое конечное определение теоретически способно описывать бесконечно большое число объектов. С помощью рекурсивной программы же возможно описать бесконечное вычисление, причём без явных повторений частей программы.
Займемся теперь непосредственно методом, реализующим алгоритм и перекладывающим кольца в соответствии с правилами игры. Написать нерекурсивный вариант ханойских башен совсем не просто. Можно, конечно, написать цикл, завершающийся по достижению требуемой конфигурации, на каждом шаге которого выполняется очередной ход. Но даже первый ход не тривиален. Поскольку фиксирован столб, где должны быть собраны кольца, то неясно, куда нужно переложить первое кольцо - на второй или третий столб?
Рекурсивный вариант решения задачи прозрачен, хотя и напоминает некоторый род фокуса, что характерно для рекурсивного стиля мышления. Базис рекурсии прост. Для перекладывания одного кольца задумываться о решении не нужно - оно делается в один ход. Если есть базисное решение, то оставшаяся часть также очевидна. Нужно применить рекурсивно алгоритм, переложив n-1 кольцо с первой пирамиды на третью пирамиду. Затем сделать очевидный ход, переложив последнее самое большое кольцо с первой пирамиды на вторую. Затем снова применить рекурсию, переложив n-1 кольцо с третьей пирамиды на вторую пирамиду. Задача решена.
Рис. 2 (блок-схема алгоритма)
5. Сложность и затраты времени
Проведем анализ временных затрат для ханойских башен (и всех задач, сводящихся к решению двух подзадач размерности n-1). Подсчитаем требуемое число ходов T(n). С учетом структуры решения:
T(n) = +1
Простое доказательство по индукции дает:
T(n) = -1 + -2 + … + 2 +1 = -1
Можно показать, что последовательность ходов, реализуемая рекурсивным алгоритмом, является оптимальной, так что никакой другой алгоритм не может решить задачу за меньшее число ходов.
Алгоритм решения задачи о Ханойских башнях является конечным, так как все используемые циклы выполняются конечное число раз.
Сложность - количественная характеристика алгоритма, которая говорит о том, сколько времени он работает (временная сложность), либо о том, какой объем памяти он занимает (емкостная сложность). На практике сложность рассматривают как временную сложность.
Из определения сложности следует, что она зависит от размерности входных данных или, как говорят, от длины входа. В задаче о Ханойских башнях входными данными является число дисков.
Рассчитаем порядок временной сложности в соответствии с пошаговым алгоритмом.
Временная сложность процедуры будет зависеть от количества переносов, которое равно 2n-1, значит О(2n-1).
6. Связь задачи «Ханойские башни» с теорией графов
Если внимательно вдуматься в задачу, то можно предположить, что все диски можно переложить на стержень (2) с помощью стержня (3) и наоборот. Т.е. у нас появляется выбор. Следовательно есть несколько способов решить эту задачу.
Еще одно замечательное следствие состоит в том, что в процессе перекладывания колец встретятся все допустимые расположения колец на трёх стержнях, так сказать, «все позиции». Почему это можно утверждать?
Потому, что общее число позиций равно 2n (чтобы задать позицию, мы для каждого из n колец должны выбрать тот из трёх стержней, на котором оно в этой позиции находится - а порядок колец на стержне жёстко задан их размерами), и по той простой причине, что никакая позиция не встречается в процессе перекладывания дважды (иначе процесс можно было бы сократить). А поскольку мы вынуждены делать именно (2n - 1) ходов, каждый раз получая неповторяющиеся позиции, то все позиции будут получены.
В задаче было показано, что путь от исходного (все кольца собраны на левом стержне) до конечного (все кольца собраны на правом из трех стержней) состояния проходит абсолютно через все допустимые позиции. Осталось только осмыслить, как именно это происходит. Для этого надо изобразить все возможные позиции игры в виде графа:
Рис. 3 (граф, демонстрирующий выбор позиций дисков)
На рис. 3 показаны графы H1-H4 башен с числом колец от 1 до 4. Ходы по сторонам самых маленьких треугольников соответствуют переносу самого маленького кольца, ходы между такими треугольниками (но внутри треугольника следующего размера) - переносу следующего кольца, и т. д. Это в стандартной головоломке, когда все переносы разрешены. А что получается, если между стержнями A и С ничего переносить нельзя?
Картинка с изображением графа, который получается из H3, приведена на рис. 4:
Рис. 4 (ограниченный условием граф)
Попробуем понять, почему граф «обрезается» именно так, как показано на этой картинке. Для этого «укрупним» изображения точек на исходном графе и поместим на них информацию о том, какому расположению колец соответствует данная точка (рис. 5):
Рис. 5 (граф с координатами дисков)
Здесь «cbb», например, означает, что самое маленькое кольцо находится на стержне C, а оба остальных - на стержне B. При этом можно либо перенести маленькое кольцо (в стандартном графе - на любой из стержней A или B, то есть получить abb или bbb), либо перенести следующее кольцо на свободный стержень (то есть получить cab). В новой версии переносы с A на C и с C на A запрещены, так что ровно один из этих трех ходов оказывается невозможным, - а это означает, что каждая позиция, кроме первой и последней, имеет ровно две соседних. Тем самым весь путь по графу оказывается одной длинной ломаной линией без всяких ответвлений.
Интересно, что построенный нами путь по графу (точнее, его буквенная запись вида aaa - baa -... - ccc) встречается в очень многих серьезных математических (и не только математических) исследованиях и носит специальное название - код Грея. Главная особенность кодов Грея состоит в том, что соседние значения в последовательности «кодовых слов» отличаются только в одном разряде.
7. Применение кода Грея для решения
башня рекурсия граф головоломка
Коды Грея применяются в решении задачи о Ханойских башнях. Пусть N - количество дисков. Начнём с кода Грея длины N, состоящего из одних нулей (то есть G(0)), и будем двигаться по кодам Грея (от G(i) переходить к G(i+1)). Поставим в соответствие каждому I-ому биту текущего кода Грея I-ый диск (причём самому младшему биту соответствует наименьший по размеру диск, а самому старшему биту - наибольший).
Поскольку на каждом шаге изменяется ровно один бит, то мы можем понимать изменение бита I как перемещение I-го диска. Заметим, что для всех дисков, кроме наименьшего, на каждом шаге имеется ровно один вариант хода (за исключением стартовой и финальной позиций). Для наименьшего диска всегда имеется два варианта хода, однако имеется стратегия выбора хода, всегда приводящая к ответу: если N нечётно, то последовательность перемещений наименьшего диска имеет вид f->t->r->f->t->r->… (где f-стартовый стержень, t-финальный стержень, r-оставшийся стержень), а если N чётно, то f->r->t->f->r->t->…
8. Различные задачи с измененным условием
Ханойские башни - старая задача и она уже давно решена, поэтому сейчас существует уже много задач, условие которых было изменено или доработано для усложнения.
В данной курсовой работе были рассмотрены некоторые из них:
1) Постановлением ЮНЕСКО оригинал Ханойской башни был подвергнут реставрации. В связи с этим во время пользования головоломкой нельзя было перекладывать кольца с первого стержня сразу на третий и наоборот.
Решите головоломку (переложите все кольца с первого стержня на третий) с учетом этих ограничений. Вам не нужно находить минимальное решение, но количество совершенных перемещений не должно быть больше 200000, при условии, что количество дисков не превосходит 10.Каждое перемещение задается тремя числами: номер кольца, исходный стержень, конечный стержень (приложение 3).
2) На дорогах Ханоя было введено одностороннее круговое движение, поэтому теперь диск со стержня 1 можно перекладывать только на стержень 2, со стержня 2 на 3, а со стержня 3 на 1.
Решите головоломку с учетом этих ограничений. Вам не нужно находить минимальное решение, но количество совершенных перемещений не должно быть больше 200000, при условии, что количество дисков не превосходит 10 (приложение 5).
Заключение
Во время выполнения курсовой работы мною были изучены следующие вопросы:
1) Алгоритм рекурсии;
2) Код Грея;
3) Связь задачи «Ханойские Башни» с теорией графов;
4) Некоторые методы работы с языком программирования С# ;
Мной была составлена программа для наглядного представления работы рекурсии на примере задачи о Ханойских башнях на С# в VisualStudio 2010. После проведённых тестов, был сделан вывод, что программа работает корректно, следовательно, поставленная задача выполнена.
Список используемой литературы
1. С. М. Окулов, А. В. Лялин «Ханойские Башни» 2008г. 248 стр.
2. Сайт «Wikipedia» http://ru.wikipedia.org/wiki/Ханойская_башня
3. Сайт «элементы» http://elementy.ru/problems/441
4. Сайт «С# Programming» http://www.c-help.net/142.html
5. Сайт informatics.mccme http://informatics.mccme.ru/moodle/mod/statements/ view3.php?id=2550&chapterid=3050
Нормативные ссылки
6. В данной пояснительной записке использованы ссылки на следующие стандарты:
7. ГОСТ Р 1.5-2004. Стандарты национальные РФ. Правила построения, изложения, оформления и обозначения.
8. ГОСТ 2.301-68 ЕСКД. Форматы.
9. ГОСТ Р 7.0.5-2008 СИБИД. Библиографическая ссылка. Общие требования и правила составления.
10. ГОСТ 7.12-93 СИБИД. Библиографическая запись. Сокращения слов на русском языке. Общие требования и правила.
11. ГОСТ 7.9-95 СИБИД. Реферат и аннотация. Общие требования.
12. ГОСТ 7.82-2001 СИБИД. Библиографическая запись. Библиографическое описание электронных ресурсов. Общие требования и правила составления.
Приложение 1
Код программы на языке C#
using System;
using System.Collections.Generic;
using System.Text;
namespace Hanoi
{
class Program
{
static void Main(string[] args)
{
int x;
double y = 0;
char from = 'A', to = 'B', help = 'C';
do
{
try
{
Console.Write(" Введите количество дисков: ");
x = Convert.ToInt32(Console.ReadLine());
}
catch (FormatException e)
{
x = -10;
}
} while (x == -10 || x > 10);
Console.WriteLine("Перемещения:");
hanoi(x, from, to, help);
Console.Read();
y = (Math.Pow(2, x)-1);
Console.WriteLine("Было совершено {0} движений",y);
}
static void hanoi(int x, char from, char to, char help)
{
if (x > 0)
{
hanoi(x - 1, from, help, to);
move(x, from, to);
hanoi(x - 1, help, to, from);
}
}
static void move(int x, char from, char to)
{
Console.WriteLine(" Передвигаем диск " + x + " с " + from + " на " + to);
}}}
Приложение 2
Пояснения к программе:
1)Вводим количество дисков.
2) Жмем Enter, после чего получаем все перемещения, которые совершала программа.
3)После вычисления нажимаем Enter и появляется количество перемещений в идеале, совершенных программой.
Приложение 3
Код программы 2 на языке C#
(Program)
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
namespace HanoiB
{
class Program
{
static void Main()
{
int discsCount = int.Parse(Console.ReadLine());
Towers towers = new Towers(
3,
(towerNo) => { if (towerNo == 0) return discsCount; return 0; },
(towerNo, discNo) => { if (towerNo == 0) return discNo + 1; return 0; },
Console.Out);
towers.AddConditions((TowerSrc, TowerDest, Towers) =>
{
return Towers.GetDisksCount(TowerSrc) != 0
&& (Towers.GetDisksCount(TowerDest) == 0
|| Towers.GetTopDiscRadius(TowerSrc) < Towers.GetTopDiscRadius (TowerDest));
});
towers.AddConditions((TowerSrc, TowerDest, Towers) =>
{
return TowerSrc == Strategy.SecondTower || TowerDest == Strategy.SecondTower;
});
Strategy strategy = new Strategy(towers);
strategy.TransferN(discsCount);
}
}
}
(Strategy)
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Diagnostics;
namespace HanoiB
{
/// <summary>
/// НЕОБХОДИМО СОБЛЮДЕНИЯ ИНВАРИАНТА: ЕСЛИ ДИСК N-1 ЛЕЖИТ НЕ ЛЕЖИТ НАД
/// ДИСКОМ N ТО НАД ДИСКОМ N НЕТ ДРУГИХ ДИСКОВ.
/// </summary>
class Strategy
{
public const int FirstTower = 0;
public const int SecondTower = 1;
public const int ThirdTower = 2;
private Towers towers;
public Strategy(Towers towers)
{
Trace.Assert(towers.TowersCount == 3);
this.towers = towers;
}
public void TransferN(int n)
{
Transfer12(n);
Transfer23(n);
//if (n != 1)
//{
// Transfer12(n - 1);
// Transfer23(n - 1);
//}
//towers.Transfer(FirstTower, SecondTower);
//if (n != 1)
//{
// Transfer32(n - 1);
// Transfer21(n - 1);
//}
//towers.Transfer(SecondTower, ThirdTower);
}
private void Transfer12(int n)
{
if (towers.IsContainRadius(SecondTower, n))
return;
Debug.Assert(towers.IsContainRadius(FirstTower, n));
if (n != 1)
{
Transfer12(n - 1);
Transfer23(n - 1);
}
towers.Transfer(FirstTower, SecondTower);
if (n != 1)
{
Transfer32(n - 1);
}
}
private void Transfer21(int n)
{
if (towers.IsContainRadius(FirstTower, n))
return;
Debug.Assert(towers.IsContainRadius(SecondTower, n));
if (n != 1)
{
Transfer12(n - 1);
Transfer23(n - 1);
}
towers.Transfer(SecondTower, FirstTower);
if (n != 1)
{
Transfer32(n - 1);
Transfer21(n - 1);
}
}
private void Transfer23(int n)
{
if (towers.IsContainRadius(ThirdTower, n))
return;
Debug.Assert(towers.IsContainRadius(SecondTower, n));
if (n != 1)
{
Transfer32(n - 1);
Transfer21(n - 1);
}
towers.Transfer(SecondTower, ThirdTower);
if (n != 1)
{
Transfer12(n - 1);
Transfer23(n - 1);
}
}
private void Transfer32(int n)
{
if (towers.IsContainRadius(SecondTower, n))
return;
Debug.Assert(towers.IsContainRadius(ThirdTower, n));
if (n != 1)
{
Transfer32(n - 1);
Transfer21(n - 1);
}
towers.Transfer(ThirdTower, SecondTower);
if (n != 1)
{
Transfer12(n - 1);
}
}
}
}
(Towers)
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.IO;
using System.Diagnostics;
namespace HanoiB
{
sealed class Towers
{
private Stack<int>[] towers;
private TextWriter outStream;
private IList<Func<int, int, Towers, bool>> TransferConds;
public void AddConditions(Func<int, int, Towers, bool> transferCond)
{
this.TransferConds.Add(transferCond);
}
public void RemoveConditions(Func<int, int, Towers, bool> transferCond)
{
this.TransferConds.Remove(transferCond);
}
public bool CheckTransferConds(int towerSrc, int towerDest)
{
foreach (Func<int, int, Towers, bool> cond in TransferConds)
{
if (false == cond(towerSrc, towerDest, this))
return false;
}
return true;
}
public Towers(
byte count,
Func<int, int> getDiscsCount,
Func<int, int, int> getRadius,
TextWriter outStream)
{
towers = new Stack<int>[count];
for (int towerNo = 0; towerNo < count; towerNo++)
{
towers[towerNo] = new Stack<int>();
for (int discNo = getDiscsCount(towerNo) - 1; discNo >= 0; discNo--)
towers[towerNo].Push(getRadius(towerNo, discNo));
}
this.outStream = outStream;
this.TransferConds = new List<Func<int, int, Towers, bool>>();
}
public int TowersCount
{
get { return towers.Length; }
}
public int GetDisksCount(int towerNo)
{
return towers[towerNo].Count;
}
public int GetTopDiscRadius(int towerNo)
{
return towers[towerNo].Peek();
}
public int FindTowerWithRadius(int radius)
{
for (int i = 0; i < TowersCount - 1; i++)
if (IsContainRadius(i, radius))
return i;
throw new ArgumentException("Towers doesn't contain radius " + radius);
}
public bool IsContainRadius(int towerNo, int radius)
{
return towers[towerNo].Contains(radius);
}
public void Transfer(int towerSrc, int towerDest)
{
Trace.Assert(CheckTransferConds(towerSrc, towerDest));
towers[towerDest].Push(towers[towerSrc].Pop());
outStream.WriteLine("{0} {1} {2}", GetTopDiscRadius(towerDest), towerSrc + 1, towerDest + 1);
}
}
}
Приложение 4
Пояснения к программе 2:
1)Вводим количество дисков.
2) Жмем Enter, после чего получаем все перемещения, которые совершала программа.
Приложение 5
Код программы 3 на языке C#
(Program)
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
namespace HanoiC
{
class Program
{
static void Main()
{
int discsCount = int.Parse(Console.ReadLine());
Towers towers = new Towers(
3,
(towerNo) => { if (towerNo == 0) return discsCount; return 0; },
(towerNo, discNo) => { if (towerNo == 0) return discNo + 1; return 0; },
Console.Out);
towers.AddConditions((TowerSrc, TowerDest, Towers) =>
{
return Towers.GetDisksCount(TowerSrc) != 0
&& (Towers.GetDisksCount(TowerDest) == 0
|| Towers.GetTopDiscRadius(TowerSrc) < Towers.GetTopDiscRadius (TowerDest));
});
towers.AddConditions((TowerSrc, TowerDest, Towers) =>
{
return (TowerSrc == Strategy.ThirdTower && TowerDest == Strategy.FirstTower)
|| (TowerDest-TowerSrc==1);
});
Strategy strategy = new Strategy(towers);
strategy.TransferN(discsCount);
}
}
}
(Strategy)
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Diagnostics;
namespace HanoiC
{
class Strategy
{
public const int FirstTower = 0;
public const int SecondTower = 1;
public const int ThirdTower = 2;
private Towers towers;
public Strategy(Towers towers)
{
Trace.Assert(towers.TowersCount == 3);
this.towers = towers;
}
public void TransferN(int n)
{
Transfer12(n);
Transfer23Full(n);
}
private void Transfer12(int n)
{
if (towers.IsContainRadius(SecondTower, n))
return;
Trace.Assert(towers.IsContainRadius(FirstTower, n));
if (n != 1)
{
Transfer12(n - 1);
Transfer23Full(n - 1);
}
towers.Transfer(FirstTower, SecondTower);
}
private void Transfer12Full(int n)
{
Transfer12(n);
if (n != 1)
{
Transfer31(n - 1);
Transfer12Full(n - 1);
}
}
private void Transfer23(int n)
{
if (towers.IsContainRadius(ThirdTower, n))
return;
Trace.Assert(towers.IsContainRadius(SecondTower, n));
if (n != 1)
{
Transfer23(n - 1);
Transfer31Full(n - 1);
}
towers.Transfer(SecondTower, ThirdTower);
}
private void Transfer23Full(int n)
{
Transfer23(n);
if (n != 1)
{
Transfer12(n - 1);
Transfer23Full(n - 1);
}
}
private void Transfer31(int n)
{
if (towers.IsContainRadius(FirstTower, n))
return;
Trace.Assert(towers.IsContainRadius(ThirdTower, n));
if (n != 1)
{
Transfer31(n - 1);
Transfer12Full(n - 1);
}
towers.Transfer(ThirdTower, FirstTower);
}
private void Transfer31Full(int n)
{
Transfer31(n);
if (n != 1)
{
Transfer23(n - 1);
Transfer31Full(n - 1);
}
}
}
}
(Towers)
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.IO;
using System.Diagnostics;
namespace HanoiC
{
sealed class Towers
{
private Stack<int>[] towers;
private TextWriter outStream;
private IList<Func<int, int, Towers, bool>> TransferConds;
public void AddConditions(Func<int, int, Towers, bool> transferCond)
{
this.TransferConds.Add(transferCond);
}
public void RemoveConditions(Func<int, int, Towers, bool> transferCond)
{
this.TransferConds.Remove(transferCond);
}
public bool CheckTransferConds(int towerSrc, int towerDest)
{
foreach (Func<int, int, Towers, bool> cond in TransferConds)
{
if (false == cond(towerSrc, towerDest, this))
return false;
}
return true;
}
public Towers(
byte count,
Func<int, int> getDiscsCount,
Func<int, int, int> getRadius,
TextWriter outStream)
{
towers = new Stack<int>[count];
for (int towerNo = 0; towerNo < count; towerNo++)
{
towers[towerNo] = new Stack<int>();
for (int discNo = getDiscsCount(towerNo) - 1; discNo >= 0; discNo--)
towers[towerNo].Push(getRadius(towerNo, discNo));
}
this.outStream = outStream;
this.TransferConds = new List<Func<int, int, Towers, bool>>();
}
public int TowersCount
{
get { return towers.Length; }
}
public int GetDisksCount(int towerNo)
{
return towers[towerNo].Count;
}
public int GetTopDiscRadius(int towerNo)
{
return towers[towerNo].Peek();
}
public int FindTowerWithRadius(int radius)
{
for (int i = 0; i < TowersCount - 1; i++)
if (IsContainRadius(i, radius))
return i;
throw new ArgumentException("Towers doesn't contain radius " + radius);
}
public bool IsContainRadius(int towerNo, int radius)
{
return towers[towerNo].Contains(radius);
}
public void Transfer(int towerSrc, int towerDest)
{
Trace.Assert(CheckTransferConds(towerSrc, towerDest));
towers[towerDest].Push(towers[towerSrc].Pop());
outStream.WriteLine("{0} {1} {2}", GetTopDiscRadius(towerDest), towerSrc + 1, towerDest + 1);
}
}
}
Приложение 6
Пояснения к программе 3:
1)Вводим количество дисков.
2) Жмем Enter, после чего получаем все перемещения, которые совершала программа.
Размещено на Allbest.ru
Подобные документы
Ханойские башни: постановка задачи, условия перемещения дисков со стержня на стержень. Стратегия решения, используемые предикаты. Текст программы на языке Пролог. Построение модели решения задачи о ферзях. Примеры использования списков в языке Пролог.
презентация [72,0 K], добавлен 29.07.2012Исследование правил интеллектуальной игры "Ханойская башня". Описания алгоритма решения задачи на языке программирования Пролог. Характеристика компиляции и запуска программы с решением для трёх дисков. Изучение работы визуализатора, написание скрипта.
курсовая работа [672,6 K], добавлен 13.06.2012Краткий обзор решения транспортных задач. Экономическая интерпретация поставленной задачи. Разработка и описание алгоритма решения задачи. Построение математической модели. Решение задачи вручную и с помощью ЭВМ. Анализ модели на чувствительность.
курсовая работа [844,3 K], добавлен 16.06.2011Нахождение высоты конуса наименьшего объема, описанного около данного шара радиуса. Определение исследуемой функции, зависящей от одной переменной. Составление математической модели задачи. Построение графика заданной функции с помощью MS Excel.
задача [3,2 M], добавлен 15.02.2010Построения математической модели с целью получения максимальной прибыли предприятия, графическое решение задачи. Решение задачи с помощью надстройки SOLVER. Анализ изменений запасов ресурсов. Определение пределов изменения коэффициентов целевой функции.
курсовая работа [2,4 M], добавлен 17.12.2014Построение математической модели. Выбор, обоснование и описание метода решений прямой задачи линейного программирования симплекс-методом, с использованием симплексной таблицы. Составление и решение двойственной задачи. Анализ модели на чувствительность.
курсовая работа [100,0 K], добавлен 31.10.2014Решение задачи на составление компромиссного списка. Построение математической модели. Цена перемещения элементов. Вывод программы. Закреплении элемента а1 на первом месте, а а4 на пятом. Матрица оценок для задачи. Оптимальное решение в виде списка.
курсовая работа [37,5 K], добавлен 30.01.2016Решение задачи линейного программирования симплекс-методом: постановка задачи, построение экономико-математической модели. Решение транспортной задачи методом потенциалов: построение исходного опорного плана, определение его оптимального значения.
контрольная работа [118,5 K], добавлен 11.04.2012Математическая модель задачи: расчет объема производства, при котором средние постоянные издержки минимальны. Построение графика функции с помощью графического редактора MS Excel. Аналитическое исследование функции, зависящей от одной переменной.
курсовая работа [599,7 K], добавлен 13.02.2010Решение в среде Microsoft Excel с помощью программной модели "Поиск решения" транспортной задачи, системы нелинейных уравнений, задачи о назначениях. Составление уравнения регрессии по заданным значениям. Математические и алгоритмические модели.
лабораторная работа [866,6 K], добавлен 23.07.2012