Регистрация не е нужна, освен при създаване на тема в "Задача на седмицата".

Обхождане на шахматна дъска с ход на коня

Обхождане на шахматна дъска с ход на коня

Мнениеот Гост » 18 Май 2024, 19:41

Задачата е кон да обходи шахматна дъска с NxN полета, като стъпи по веднъж на всяко поле и се върне в първоначалното, т.е. първото и последното поле да са свързани с ход на коня.

За съжаление алгоритъмът, който успях да измисля (долната програма на C#), е със сложност $O(8^{N^2})$ и при $N=6$ изведе схемата на ходовете след няколко минути, а при $N=7$ така и не я дочаках.

Дали няма по-бърз алгоритъм?

Код: Избери целия код
namespace Ход_на_коня
{
    public partial class Form1 : Form
    {
        private const int N = 6;
        private Point[] numberPositions;
        private bool[,] H;
        private Point[][] coordinates;
        bool active;
        public Form1()
        {
            InitializeComponent();
            Random random = new Random();
            numberPositions = new Point[N * N];
            coordinates = new Point[N * N][];
            for (int i = 0; i < N * N; i++)
            {
                coordinates[i] = new Point[] { new Point(-2, -1), new Point(-1, -2), new Point(1, -2), new Point(2, -1), new Point(2, 1), new Point(1, 2), new Point(-1, 2), new Point(-2, 1) };
                for (int c = 0; c < 12; c++)
                {
                    int u = random.Next(8); int v = random.Next(8);
                    (coordinates[i][u], coordinates[i][v]) = (coordinates[i][v], coordinates[i][u]);
                }
            }
            H = new bool[N, N];
            for (int i = 0; i < N; i++)
                for (int j = 0; j < N; j++)
                    H[i, j] = false;
            active = true;
            HorseMove(0, random.Next(N), random.Next(N));
        }

        private void HorseMove(int n, int row, int col)
        {
            if (active && row >= 0 && row < N && col >= 0 && col < N && !H[row, col])
            {
                H[row, col] = true;
                numberPositions[n] = new Point(col, row);
                if (n < N * N - 1)
                {
                    int i = N * row + col;
                    for (int j = 0; j < 8; j++)
                        HorseMove(n + 1, row + coordinates[i][j].Y, col + coordinates[i][j].X);
                }
                else
                {
                    int deltaX = Math.Abs(numberPositions[n].X - numberPositions[0].X);
                    int deltaY = Math.Abs(numberPositions[n].Y - numberPositions[0].Y);
                    if (deltaX == 1 && deltaY == 2 || deltaX == 2 && deltaY == 1)
                    {
                        active = false;
                        this.Invalidate();
                    }
                }
                H[row, col] = false;
            }
        }

        private void Form1_Paint(object sender, PaintEventArgs e)
        {
            if (!active)
            {
                float w = ClientSize.Width, h = ClientSize.Height;
                for (int i = 0; i <= N; i++)
                {
                    e.Graphics.DrawLine(new Pen(Color.Brown, (w + h) / 270),
                        w / 12, h / 12 + 5 * h / 6 * i / N,
                        w / 12 + 5 * w / 6, h / 12 + 5 * h / 6 * i / N);
                    e.Graphics.DrawLine(new Pen(Color.Brown, (w + h) / 270),
                        w / 12 + 5 * w / 6 * i / N, h / 12,
                        w / 12 + 5 * w / 6 * i / N, h / 12 + 5 * h / 6);
                }
                PointF[] points = new PointF[N * N];
                for (int num = 0; num < N * N; num++)
                    if (numberPositions[num].X >= 0 && numberPositions[num].Y >= 0)
                    {
                        float x = w / 12 + 5 * w / 6 / N * (numberPositions[num].X + 0.2f);
                        float y = h / 12 + 5 * h / 6 / N * (numberPositions[num].Y + 0.2f);
                        float sizeNumber = (w + h) / N;
                        Font font;
                        SizeF size;
                        do
                        {
                            sizeNumber -= 0.1f;
                            font = new Font("Arial", sizeNumber, FontStyle.Italic);
                            size = e.Graphics.MeasureString("" + (num + 1), font);
                        }
                        while (size.Width > 5 * w / 6 / N * 0.6f || size.Height > 5 * h / 6 / N * 0.6f);
                        e.Graphics.DrawString("" + (num + 1), font, Brushes.Black, x, y);
                        x = w / 12 + 5 * w / 6 / N * (numberPositions[num].X + 0.5f);
                        y = h / 12 + 5 * h / 6 / N * (numberPositions[num].Y + 0.5f);
                        points[num] = new PointF(x, y);
                    }
                e.Graphics.DrawPolygon(new Pen(Color.Red, (w + h) / 290), points);
            }
        }

        private void Form1_Resize(object sender, EventArgs e)
        {
            this.Invalidate();
        }
    }
}


Ето какво излезе при $N=6$:

Ход на коня.png
Ход на коня.png (40.25 KiB) Прегледано 261 пъти
Гост
 

Re: Обхождане на шахматна дъска с ход на коня

Мнениеот ptj » 19 Май 2024, 02:33

Със сигурност има:
1.) Имайки решение за дъска [tex]N x N[/tex] е много вероятно използвайки симетриите може да намериш решение за дъска [tex](2N) x (2N)[/tex].
2.) При подобни задачи най-ефективния алгоритъм обикновено е [tex]BACKTRACK[/tex], a подходяща структура за запазване на текущата конфигурация е списък. Колкото до самото обхождане за да е по-бързо може да използваш някоя от вградените библиотеки на MFC.
3.) Добре е първо да намериш учебник "Алгоритми" на MIT и да го разгледаш детайлно.

П.П. Далеч съм от програмирането вече доста години, но когато се учех най-добрата база за мен бяха призовите решеният на различни конкурси по информатика. Например на студентските олимпиади СУ винаги имаше отбор с брилиантни решения. ;)
ptj
Математик
 
Мнения: 3305
Регистриран на: 26 Юли 2010, 19:17
Рейтинг: 1111

Re: Обхождане на шахматна дъска с ход на коня

Мнениеот peyo » 19 Май 2024, 05:55

Гост написа:Задачата е кон да обходи шахматна дъска с NxN полета, като стъпи по веднъж на всяко поле и се върне в първоначалното, т.е. първото и последното поле да са свързани с ход на коня.

За съжаление алгоритъмът, който успях да измисля (долната програма на C#), е със сложност $O(8^{N^2})$ и при $N=6$ изведе схемата на ходовете след няколко минути, а при $N=7$ така и не я дочаках.

Дали няма по-бърз алгоритъм?...


Double_Facepalm_by_ScotlandForLife.jpg
Double_Facepalm_by_ScotlandForLife.jpg (31.67 KiB) Прегледано 240 пъти
peyo
Математик
 
Мнения: 1737
Регистриран на: 16 Мар 2019, 09:35
Местоположение: София
Рейтинг: 646

Re: Обхождане на шахматна дъска с ход на коня

Мнениеот Гост » 19 Май 2024, 10:46

Благодаря на ptj за насоките.
Гост
 


Назад към Алгоритми



Кой е на линия

Регистрирани потребители: Google [Bot]

Форум за математика(архив)