Русский
Русский
English
Статистика
Реклама

Recovery mode Найти комбинацию соседних чисел, имеющих самое большое произведение


Перед вами таблица (20x20) с целым числом от 0 до 99 в каждой из клеток.
Задача найти 4 соседних числа без разрыва цепочки, одно за другим, имеющих самое большое произведение. Цветом выделены различные варианты 4 соседних чисел (соседними считаются два числа, расположенных не более чем на 1 клетку друг от друга)
Сегодня мы с вами реализуем алгоритм поиска на языке C#

Для начало создадим двумерный массив 20х20 и запишем его в файл
static void CreateArrayFile(){    Random random = new Random();    string file = "";    for (int i = 0; i < 20; i++)    {        string line = "";        for (int j = 0; j < 20; j++)        {            line += random.Next(0, 99) + ",";        }        line = line + Environment.NewLine;        file += line;    }    using (FileStream fstream = new FileStream($"array.txt", FileMode.OpenOrCreate))    {        byte[] array = System.Text.Encoding.Default.GetBytes(file);        fstream.Write(array, 0, array.Length);        Console.WriteLine("Массив записан в файл");    }}


Теперь мы можем, записать числа из файла в двумерный массив.
string[] lines = arrayFile.Split(Environment.NewLine);for (int i = 0; i < 20; i++){    string[] items = lines[i].Split(',');    for (int j = 0; j < 20; j++)    {        table[i, j] = Convert.ToInt32(items[j]);    }}

Для представления координат и значения числа создадим класс Element
public class Element{    public int Line { get; set; }    public int Column { get; set; }    public int Value { get; set; }}

По условиям задачи, требуется найти комбинацию произведений. Реализуем класс Multiplication для представления комбинации содержащий массив чисел и значение произведения чисел в комбинации.
public class Multiplication{    public Multiplication()    {        Elements = new Element[4];    }    public Element[] Elements { get; set; }    public int Value    {        get        {            Multiply();            return value;        }    }    int value;    void Multiply()    {        if(Elements[0] != null && Elements[1] != null && Elements[2] != null && Elements[3] != null)        {            value = Elements[0].Value * Elements[1].Value * Elements[2].Value * Elements[3].Value;        }    }}

Первое что нужно сделать найти ближайших соседей числа. Например, для числа 40 в нашем случае следующие соседи:

А у числа 48 в правом нижнем углу есть всего 3 соседа. Не трудно понять, что соседи любого числа это
table[i-1][j-1]table[i-1][j]table[i-1][j+1]table[i][j-1]table[i][j+1]table[i+1][j-1]table[i+1][j]table[i+1][j+1]

Убедившись, что индекс не находится вне границ, получаем метод FindNeighbors возвращающий коллекцию всех ближайших соседей конкретного числа.
По условию задачи, нам нужно найти комбинацию из 4 соседних чисел. Для этого нам нужен метод для поиска всех возможных комбинаций из 4 чисел
static List<Multiplication> GetFactorCombinations(int line, int column){    List<Multiplication> combinations = new List<Multiplication>();    if (table[line, column] != 0)    {        List<Element> firstLevelNeighbors = FindNeighbors(line, column);        foreach (var firstLevelNeighbor in firstLevelNeighbors)        {            Element[] elements = new Element[4];            elements[0] = new Element            {                Line = line,                Column = column,                Value = table[line, column]            };            elements[1] = firstLevelNeighbor;            List<Element> secondLevelNeighbors = FindNeighbors(firstLevelNeighbor.Line, firstLevelNeighbor.Column);            foreach (var secondLevelNeighbor in secondLevelNeighbors)            {                if (!elements[0].Equals(secondLevelNeighbor) && !elements[1].Equals(secondLevelNeighbor))                {                    elements[2] = secondLevelNeighbor;                }                if (elements[2] != null)                {                    List<Element> thirdLevelNeighbors = FindNeighbors(secondLevelNeighbor.Line, secondLevelNeighbor.Column);                    foreach (var thirdLevelNeighbor in thirdLevelNeighbors)                    {                        if (!elements[0].Equals(thirdLevelNeighbor) && !elements[1].Equals(thirdLevelNeighbor) && !elements[2].Equals(thirdLevelNeighbor))                        {                            elements[3] = thirdLevelNeighbor;                            Multiplication multiplication = new Multiplication                             {                                 Elements = elements                            };                            if (combinations.Where(p=>p.Elements[0].Value==elements[0].Value&& p.Elements[1].Value == elements[1].Value && p.Elements[2].Value == elements[2].Value && p.Elements[3].Value == elements[3].Value).FirstOrDefault()==null)                            {                                var nnnn =new Multiplication                                {                                    Elements = new Element[] { elements[0], elements[1], elements[2], elements[3]}                                };                                combinations.Add(nnnn);                            }                        }                    }                }            }        }    }    return combinations;}

Метод получает координаты числа в таблице и проверяет значение этого числа на 0 (При умножении любого числа на 0 всегда получается 0). Потом метод ищет всех соседей данного числа. Перебираем соседей первого уровня, в случае если число не 0 ищем всех соседей второго уровня
Переопределяем метод Equals для сравнивания чисел:
public override bool Equals(Object obj){    if (this==null || (obj == null) || !this.GetType().Equals(obj.GetType()))    {        return false;    }    else if(Line == ((Element)obj).Line && Column == ((Element)obj).Column)    {        return true;    }    else    {        return false;    }}

Продолжаем поиск до соседей четвертого уровня если числа не дублируются, то добавляем его в нашу коллекцию.
if (!elements[0].Equals(thirdLevelNeighbor) && !elements[1].Equals(thirdLevelNeighbor) && !elements[2].Equals(thirdLevelNeighbor)){    elements[3] = thirdLevelNeighbor;    Multiplication multiplication = new Multiplication     {         Elements = elements    };    if (combinations.Where(p=>p.Elements[0].Value==elements[0].Value&& p.Elements[1].Value == elements[1].Value && p.Elements[2].Value == elements[2].Value && p.Elements[3].Value == elements[3].Value).FirstOrDefault()==null)    {        var combination=new Multiplication        {            Elements = new Element[] { elements[0], elements[1], elements[2], elements[3]}        };        combinations.Add(combination);    }}

Работу метода GetFactorCombinations можно визуализировать так:

Теперь перебрав наш двумерный массив ищем самую большую комбинацию чисел.
for (int i = 0; i < 20; i++){    for (int j = 0; j < 20; j++)    {        List<Multiplication> combinations = GetFactorCombinations(i, j);        foreach (var combination in combinations)        {            if (combination.Value > maxMultiplication.Value)            {                Console.WriteLine("Найдена новая самая большая комбинация " + combination.Elements[0].Value + " * " + combination.Elements[1].Value + " * " + combination.Elements[2].Value + " * " + combination.Elements[3].Value + " = " + combination.Value);                maxMultiplication = combination;            }        }    }}Console.WriteLine("Самое большое произведение четырех чисел = " + maxMultiplication.Elements[0].Value + " * " + maxMultiplication.Elements[1].Value + " * " + maxMultiplication.Elements[2].Value + " * " + maxMultiplication.Elements[3].Value + " = " + maxMultiplication.Value);

Если следующая комбинация больше чем maxMultiplication, переписываем его.

Да, мы сделали это. Мы нашли комбинацию из 4 чисел с самым большим произведением.
Фактически, мы решили задачу, но код захардкожен под конкретные условия, чисто процедурный метод. А если нам нужно будет искать из матрицы не 20 на 20, а к примеру 30 на 30 и комбинацию не из 4, а 5 чисел? каждый раз добавлять еще один вложенный цикл (для перебора всех со всеми)
Зарезервируем 2 константы для размера таблицы, и для размера искомой комбинации
const int TABLE_SIZE = 20;public const int COMBINATION_SIZE = 4;

Перепишем метод GetFactorCombinations на рекурсивный метод
static List<Multiplication> GetMultiplicationForStep(int line, int column, List<Element> otherElements = null){    List<Multiplication> resultMultiplications = new List<Multiplication>();    List<Element> resultElements = new List<Element>();     Element element = new Element    {        Column = column,        Line = line,        Value = table[line, column]    };    if (otherElements == null)    {        otherElements = new List<Element>();    }    if(otherElements!=null)    {        resultElements.AddRange(otherElements);    }    if (table[line, column] != 0)    {                        if (otherElements.Where(p => p.Equals(element)).FirstOrDefault() == null)        {            resultElements.Add(element);        }    }    if (resultElements.Count() == COMBINATION_SIZE)    {        Multiplication multiplication = new Multiplication        {            Elements = resultElements.ToArray()        };        resultMultiplications.Add(multiplication);    }    else    {        List<Element> elementNeighbors = FindNeighbors(line, column);        elementNeighbors = elementNeighbors.Where(p => !p.Equals(element)&& otherElements.Where(p=>p.Equals(element)).FirstOrDefault()==null).ToList();        List<Multiplication> newMultiplications = new List<Multiplication>();        foreach(Element neighbor in elementNeighbors)        {            // Если количество комбинаций меньше COMBINATION_SIZE рекурсивно продолжаю искать соседей...            newMultiplications.AddRange(GetMultiplicationForStep(neighbor.Line, neighbor.Column, resultElements).Where(p=>p!=null));        }        foreach(Multiplication multiplication in newMultiplications)        {            if(resultMultiplications.Where(p=>p.Value==multiplication.Value).FirstOrDefault()==null)            {                resultMultiplications.Add(multiplication);            }        }    }    return resultMultiplications;}

Метод работает по тому же принципу как и раньше только вместо вложенных циклов, рекурсивно продолжаем поиск соседей пока количество найденных элементов resultElements.Count() != COMBINATION_SIZE
После нахождения комбинации можно его красиво отобразить в консоли
for (int i = 0; i < TABLE_SIZE; i++){    for (int j = 0; j < TABLE_SIZE; j++)    {        if (maxMultiplication.Elements.Where(p => p.Line == i && p.Column == j).FirstOrDefault() != null)        {            Console.BackgroundColor = ConsoleColor.White;            Console.ForegroundColor = ConsoleColor.Black; // Тут я вывожу таблицу заново, и отображаю самую большую найденную комбинацию            Console.Write(table[i, j] + " ");            Console.ResetColor();        }        else        {            Console.Write(table[i, j] + " ");        }    }    Console.WriteLine();}



Заключение


В этой статье мы познакомились с одним из вариантов нахождения соседних комбинаций в таблице NxN.
Что можно сделать еще:
  • Можно рассмотреть возможность избавиться от множественных повторных переборов всех комбинаций со всеми, и другими способами оптимизировать код.
  • На основе существующего алгоритма реализовать поиск комбинаций соседних чисел на 3-мерном массиве. Но это уже в другой раз

Источник: habr.com
К списку статей
Опубликовано: 10.08.2020 10:05:17
0

Сейчас читают

Комментариев (0)
Имя
Электронная почта

Алгоритмы

C

С

Категории

Последние комментарии

  • Имя: Макс
    24.08.2022 | 11:28
    Я разраб в IT компании, работаю на арбитражную команду. Мы работаем с приламы и сайтами, при работе замечаются постоянные баны и лаги. Пацаны посоветовали сервис по анализу исходного кода,https://app Подробнее..
  • Имя: 9055410337
    20.08.2022 | 17:41
    поможем пишите в телеграм Подробнее..
  • Имя: sabbat
    17.08.2022 | 20:42
    Охренеть.. это просто шикарная статья, феноменально круто. Большое спасибо за разбор! Надеюсь как-нибудь с тобой связаться для обсуждений чего-либо) Подробнее..
  • Имя: Мария
    09.08.2022 | 14:44
    Добрый день. Если обладаете такой информацией, то подскажите, пожалуйста, где можно найти много-много материала по Yggdrasil и его уязвимостях для написания диплома? Благодарю. Подробнее..
© 2006-2023, personeltest.ru