6 / 2 / 1
Регистрация: 15.10.2020
Сообщений: 62
1

Как оптимизировать код

30.03.2021, 12:10. Показов 2395. Ответов 12

Author24 — интернет-сервис помощи студентам
Решал задачу с информатикса. Все работает, но на одном из тестов выдает тайм-лимит. Можно ли как-нибудь оптимизировать код? Условие на скриншоте.

Код:
C#
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
using System;
using System.IO;
using System.Collections.Generic;
 
namespace _1
{
    class Program
    {
        static void Main(string[] args)
        {
            int n, h;
            List<int> balloons = new List<int>();
            
            using (StreamReader sr = new StreamReader("input.txt"))
            {
                string s1 = sr.ReadLine();
                n = Convert.ToInt32(s1);
 
                string[] s2 = sr.ReadLine().Split(' ');
                for(int i = 0; i < n; i++)
                {
                    balloons.Add(Convert.ToInt32(s2[i]));
                }
 
                int arrows = 0, z = 0;
 
                for (int i = 0; i < balloons.Count;)
                {
                    h = balloons[i] - 1;
                    balloons.Remove(balloons[i]);
                    for (int j = i; j < balloons.Count; j++)
                    {
                        if (balloons[j] == h)
                        {
                            h = balloons[j] - 1;
                            balloons[j] = -1;
                            balloons.Remove(balloons[j]);
                            j--;
                        }
                    }
                    arrows++;
                }
                Console.WriteLine(arrows);
            }
        }
    }
}
Миниатюры
Как оптимизировать код  
0
Лучшие ответы (1)
Programming
Эксперт
94731 / 64177 / 26122
Регистрация: 12.04.2006
Сообщений: 116,782
30.03.2021, 12:10
Ответы с готовыми решениями:

Как оптимизировать код, где используется много методов .Contains?
Здравствуйте! Есть задача поиска всех url'ов на каком то сайте и найти в них битые/небитые. Задачу...

Заменить volatile на Thread.MemoryBarrier. Код приведён. Как оптимизировать обращения для чтения к volatile полю класса?
Не совсем понятна мне пока что работа Thread.MemoryBarrier. Знаю, что можно оптимизировать...

Исправить и оптимизировать код
Код: using System; using System.Collections.Generic; using System.Diagnostics; using...

Подключение к модему: оптимизировать код
Вопрос, наверное, по ООП. Предполагается, что к 4 ком-портам подключены 4 модема. На форме...

12
1213 / 804 / 244
Регистрация: 08.08.2014
Сообщений: 2,361
30.03.2021, 15:22 2
Если оставаться в рамках того же алгоритма, то желательно полностью исключить операции удаления элемента из списка, т.к. List внутри реализован поверх обычного массива и его ресайз очень ресурсоёмок.

Вариант без удаления на максимальном значении N на одном среднем ядре отрабатывает за 10-12 секунд.

Однако, полагаю, здесь так же нужно более правильный алгоритм придумать, а не только под особенности языка оптимизировать. Т.е. даже с этой оптимизацией вы вряд ли тест пройдёте на максимальном N.

Блок до основного цикла немного изменён, но это просто для удобства, на прозводительности это никак не сказывается.
Суть - вместо удаления, лопнутые шарики, по которым возможен повторный проход, помечаются значением 'int.MinValue' и далее игнорируются.
без удаления
C#
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
static void Main(string[] args)
{
    //MakeRandomTestData();
 
    var sw = Stopwatch.StartNew();
 
    using (var sr = new StreamReader("input.txt"))
    {
        var balloons = new int[Convert.ToInt32(sr.ReadLine())];
 
        var heightsRaw = sr.ReadLine().Split(' ');
        for (var i = 0; i < balloons.Length; i++)
        {
            balloons[i] = Convert.ToInt32(heightsRaw[i]);
        }
 
        var arrows = 0;
 
        for (var i = 0; i < balloons.Length; i++)
        {
            var h = balloons[i];
 
            if (h == int.MinValue)
            {
                continue;
            }
 
            h--;
 
            for (var j = i + 1; j < balloons.Length && h > 0; j++)
            {
                if (balloons[j] == int.MinValue)
                {
                    continue;
                }
 
                if (balloons[j] == h)
                {
                    balloons[j] = int.MinValue;
                    h--;
                }
            }
            arrows++;
        }
 
        Console.WriteLine(arrows);
    }
 
    sw.Stop();
 
    Console.WriteLine(sw.ElapsedMilliseconds + "ms");
    Console.ReadKey();
}


Добавлено через 1 час 5 минут
* хотя нет, проверил, если сгенерировать максимальный набор данных в полном соответствии с условиями задачи, т.е. 1млн значений со случайными высотами от 1 до 1млн, то даже этот оптимизированный алгоритм даёт крайне неудоволетворительный результат, тут явно нужчно что-то более интеллектуальное, чем простой перебор.
1
484 / 439 / 123
Регистрация: 05.01.2010
Сообщений: 1,848
30.03.2021, 18:55 3
я хз, может есть какие то специальные алгоритмы...
но в голову приходит перебирать каждый раз не с нуля, а с первого элемента, который остался необработанным после очередного прохода. и до тех пор, пока не останется необработанных элементов. в теории должно быть получше, чем квадратичная сложность
0
Эксперт .NET
17685 / 12871 / 3365
Регистрация: 17.09.2011
Сообщений: 21,136
30.03.2021, 19:54 4
Лучший ответ Сообщение было отмечено SlaTH как решение

Решение

Цитата Сообщение от SlaTH Посмотреть сообщение
Можно ли как-нибудь оптимизировать код?
Пара предположений, которые явно не оговерны в задании:
1. Шарики могут быть подвешены на одинаковой высоте.
2. Стрела может без помех пролетать выше или ниже шарика.

Девочка Перика обладает отличным глазомером, быстрым умом, зорким глазом и исключительной скорострельностью — как только выпущенная стрела коснется шарика, девочка мигом может определить высоту следующего шарика и понять: собьет ли его выпущенная ранее стрела. Если не собьет, то она сразу же запускает вслед предыдущей стреле новую, которая собьет этот шарик.
Перика держит в голове текущую высоту всех выпущенных ранее стрел и мгновенно может решать — надо ли запускать новую стрелу для ближайшего шарика, или его собьет выпущенная ранее и сейчас летящая на этой высоте.

С такими мега-способностями задачу можно решить за O(n) по времени и O(n) по памяти.
Самый первый шарик придется сбивать по-любому, как только он лопнет, сразу станет ясно: собьет ли она уже летящая стрела следующий шарик, или он находится выше/ниже и надо пускать новую. Эта проверка выполняется для каждого шарика и до победного конца:
C#
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
using System.Collections.Generic;
using static System.Console;
 
int n = ReadBalloonCount(); // Считывание количества шариков
int shotsFired = 0;
 
// Стрелы в полете. Индекс — высота полета, значение — количество стрел на этой высоте.
var arrowsInFlight = new int[n + 1];
 
IEnumerable<int> heights = ReadHeights(n); // Считывание высот шариков.
foreach (int h in heights)
{
    ref int arrowsAtHeightH = ref arrowsInFlight[h];
 
    // На этой высоте уже летит стрела
    if (arrowsAtHeightH > 0)        
        arrowsAtHeightH--; // Она собьет шарик и опустится на этаж ниже
    else
        shotsFired++; // Пускаем новую стрелу
 
    // После того, как шарик лопнул, этажом ниже стало одной стрелой больше
    arrowsInFlight[h - 1]++;
}
 
WriteLine(shotsFired);
Время выполнения можно разменять на память, заменив массив высот на словарь.
Методы ReadBalloonCount и ReadHeights можно реализовать на свой вкус для экономии времени/памяти: сплитом или считыванием поштучно
3
6 / 2 / 1
Регистрация: 15.10.2020
Сообщений: 62
30.03.2021, 20:05  [ТС] 5
Спасибо за ответ. Не разобрался, как использовать интерфейс IEnumerable. Не могли бы вы объяснить 10 строчку?
C#
1
IEnumerable<int> heights = ReadHeights(n); // Считывание высот шариков.
0
Эксперт .NET
17685 / 12871 / 3365
Регистрация: 17.09.2011
Сообщений: 21,136
30.03.2021, 20:11 6
Цитата Сообщение от SlaTH Посмотреть сообщение
Не могли бы вы объяснить 10 строчку?
Просто вызов метода, реализацию которого я оставил на ваше усмотрение.
Простейшая реализация может быть такой:
C#
1
2
IEnumerable<int> ReadHeights(int n) => 
   Console.ReadLine().Split(' ').Select(int.Parse).Take(n);
Но это не сильно хорошо по используемой памяти, если n большое.
При желании можно реализовать посимвольное считывание вручную, но мне лень было заморачиваться.

Добавлено через 1 минуту
Ваша реализация из первого сообщения выглядела бы так:
C#
1
2
3
4
5
6
7
8
9
10
IEnumerable<int> ReadHeights(int n)
{
                List<int> balloons = new List<int>();
                string[] s2 = sr.ReadLine().Split(' ');
                for(int i = 0; i < n; i++)
                {
                    balloons.Add(Convert.ToInt32(s2[i]));
                }
                return balloons;
}
1
6 / 2 / 1
Регистрация: 15.10.2020
Сообщений: 62
30.03.2021, 20:13  [ТС] 7
Спасибо!
0
2636 / 1564 / 853
Регистрация: 23.02.2019
Сообщений: 3,876
05.04.2021, 17:07 8
Ещё один вариант, скорее всего не оптимальный по скорости.
Идея в том, чтобы всегда стрелять только в самый высокий и ближний на данный момент шарик. И продолжать это делать, пока шарики существуют.

C#
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
static void Main()
{
    Random rand = new Random();
    int balloonsCount = 10;
    int maxHeight = 5;
 
    // карта высот от 1 до maxHeight
    int[] heights = Enumerable.Repeat(1, balloonsCount).Select(i => 1 + rand.Next(maxHeight)).ToArray();
 
    // вспомогательный список, в котором записаны индексы шаров, от максимальной высоты до минимальной
    Dictionary<int, int> indexValue = Enumerable.Range(0, balloonsCount).ToDictionary(i => i, i => heights[i]);
    var sortInd = indexValue.OrderByDescending(i => i.Value).Select(i => i.Key).ToArray();
 
 
    int arrows = 0;
 
    // перебираем все шарики от высокого к низкому
    for (int i = 0; i < sortInd.Length; i++)
    {
        int indexHighBall = sortInd[i];
 
        // если шарик ещё не был лопнут
        if (heights[indexHighBall] > 0)
        {
            // то выпускаем в него стрелу
            arrows++;
 
            // стрела лопает шарик
            int hightValue = heights[indexHighBall];
            heights[indexHighBall] = 0;
 
            // стрела опускается ниже
            hightValue--;
 
            // стрела летит к следующему шарику вдоль пути
            for (int j = indexHighBall + 1; j < heights.Length; j++)
            {
                // если шарик на одном уровне со стрелой
                if (heights[j] == hightValue)
                {
                    // лопаем шарик, и опускаемся ниже
                    heights[j] = 0;
                    hightValue--;
                }
            }
        }
    }
 
    Console.WriteLine(arrows);
 
}
Хотел протестировать уже предложенные варианты, чтобы сравнить со своим, но запустился только вариант от kotelok, но он почему-то выдавал большее кол-во стрел, чем нужно. А вариант от kolorotur, почему-то выдавал ошибку выхода индекса за пределы массива. Пытался исправить, но не разобрался..
1
Эксперт .NET
17685 / 12871 / 3365
Регистрация: 17.09.2011
Сообщений: 21,136
05.04.2021, 18:10 9
Цитата Сообщение от samana Посмотреть сообщение
А вариант от kolorotur, почему-то выдавал ошибку выхода индекса за пределы массива.
С какими входными данными?

Добавлено через 33 минуты
Цитата Сообщение от samana Посмотреть сообщение
Пытался исправить, но не разобрался
Я почему-то решил, что Hi ≤ N — переглючил малость.
Исправляется в 8-й строке — вместо n надо прописать константу:
C#
1
2
// Стрелы в полете. Индекс — высота полета, значение — количество стрел на этой высоте.
var arrowsInFlight = new int[1000001];
Но это как-то слишком уж легко исправляется.
Если не сложно, приведите тестовые данные, с которыми мой вариант сыпался — может там где-то еще баг засел.
1
2636 / 1564 / 853
Регистрация: 23.02.2019
Сообщений: 3,876
05.04.2021, 18:13 10
kolorotur, Просто назначил массив высот переменной heights и вставил длину этого массива везде, где была переменная n.
Я бы сбросил код сюда, но сейчас не за компьютером.

Добавлено через 2 минуты
Я почему-то решил, что Hi ≤ N — переглючил малость.
Спасибо, попробую с этим вариантом, как только будет возможность.
1
Эксперт .NET
17685 / 12871 / 3365
Регистрация: 17.09.2011
Сообщений: 21,136
05.04.2021, 18:17 11
Цитата Сообщение от samana Посмотреть сообщение
Просто назначил массив высот переменной heights и вставил длину этого массива везде, где была переменная n.
Скорее всего какой-то элемент массива имел значение, большее чем длина массива — это меня с толку одинаковый диапазон для N и для Hi сбил.
Спасибо за находку! Исправлено сообщением выше.

Как вариант, где-то в массиве heights было значение меньше единицы — тогда это баг у вас, т.к. 1 ≤ Hi ≤ 1000000.
0
2636 / 1564 / 853
Регистрация: 23.02.2019
Сообщений: 3,876
05.04.2021, 20:24 12
Цитата Сообщение от kolorotur Посмотреть сообщение
Исправляется в 8-й строке — вместо n надо прописать константу:
Да, причина была именно в этом!
Оказывается ваш вариант отрабатывает практически мгновенно на максимальных значениях! За свой вариант даже говорить не буду, так как не дождался его выполнения даже на 500К шариках...)
1
Эксперт .NET
17685 / 12871 / 3365
Регистрация: 17.09.2011
Сообщений: 21,136
05.04.2021, 20:28 13
Цитата Сообщение от samana Посмотреть сообщение
Да, причина была именно в этом!
Спасибо за подтверждение!
Как обычно, прочитал задание по диагонали.
1
05.04.2021, 20:28
IT_Exp
Эксперт
87844 / 49110 / 22898
Регистрация: 17.06.2006
Сообщений: 92,604
05.04.2021, 20:28
Помогаю со студенческими работами здесь

Как оптимизировать код?
Подскажите пожалуйста, как в данном коде избавиться от необходимости каждый раз перед...

как оптимизировать код?
Есть несколько dbf файлов. Из них в разные обьекты нужно получить список строк. Для этого написал...

Как оптимизировать код
Привет! Как можно &quot;уменьшить&quot; данный код? string filename = @&quot;test.exe&quot;; //...

Как оптимизировать код?
как привести это в красивый вид? если учесть что таких label будет over 100 А название будут...

Как оптимизировать код?
Всем добрый день) Недавно начал изучать C# и решил написать такую программу: В 50-х годах XX века...

Подскажите как оптимизировать код
Прошу помощи идей как оптимизировать код совсем нет public partial class RegistrationForm : Form...


Искать еще темы с ответами

Или воспользуйтесь поиском по форуму:
13
Ответ Создать тему
Опции темы

КиберФорум - форум программистов, компьютерный форум, программирование
Powered by vBulletin
Copyright ©2000 - 2024, CyberForum.ru