
- •Курсовая работа
- •Задание
- •Содержание
- •Нормативные ссылки
- •Введение
- •История задачи «Ханойские башни»
- •Суть задачи
- •1 2 3
- •Построение модели
- •Решение с помощью рекурсии
- •Сложность и затраты времени
- •Связь задачи «Ханойские башни» с теорией графов
- •Применение кода Грея для решения
- •Различные задачи с измененным условием
- •Заключение
- •Список используемой литературы:
Применение кода Грея для решения
Коды Грея применяются в решении задачи о Ханойских башнях. Пусть 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->…
Различные задачи с измененным условием
Ханойские башни – старая задача и она уже давно решена, поэтому сейчас существует уже много задач, условие которых было изменено или доработано для усложнения.
В данной курсовой работе были рассмотрены некоторые из них:
1) Постановлением ЮНЕСКО оригинал Ханойской башни был подвергнут реставрации. В связи с этим во время пользования головоломкой нельзя было перекладывать кольца с первого стержня сразу на третий и наоборот.
Решите головоломку (переложите все кольца с первого стержня на третий) с учетом этих ограничений. Вам не нужно находить минимальное решение, но количество совершенных перемещений не должно быть больше 200000, при условии, что количество дисков не превосходит 10.Каждое перемещение задается тремя числами: номер кольца, исходный стержень, конечный стержень (приложение 3).
2) На дорогах Ханоя было введено одностороннее круговое движение, поэтому теперь диск со стержня 1 можно перекладывать только на стержень 2, со стержня 2 на 3, а со стержня 3 на 1.
Решите головоломку с учетом этих ограничений. Вам не нужно находить минимальное решение, но количество совершенных перемещений не должно быть больше 200000, при условии, что количество дисков не превосходит 10 (приложение 5).
Заключение
Во время выполнения курсовой работы мною были изучены следующие вопросы:
Алгоритм рекурсии;
Код Грея;
Связь задачи «Ханойские Башни» с теорией графов;
Некоторые методы работы с языком программирования С# ;
Мной была составлена программа для наглядного представления работы рекурсии на примере задачи о Ханойских башнях на С# в VisualStudio 2010. После проведённых тестов, был сделан вывод, что программа работает корректно, следовательно, поставленная задача выполнена.
Список используемой литературы:
С. М. Окулов, А. В. Лялин «Ханойские Башни» 2008г. 248 стр.
Сайт «Wikipedia» http://ru.wikipedia.org/wiki/Ханойская_башня
Сайт «элементы» http://elementy.ru/problems/441
Сайт «С# Programming» http://www.c-help.net/142.html
Сайт informatics.mccme http://informatics.mccme.ru/moodle/mod/statements/view3.php?id=2550&chapterid=3050
Приложение 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, после чего получаем все перемещения, которые совершала программа.