2014 dxdy logo

Научный форум dxdy

Математика, Физика, Computer Science, Machine Learning, LaTeX, Механика и Техника, Химия,
Биология и Медицина, Экономика и Финансовая Математика, Гуманитарные науки




Начать новую тему Ответить на тему На страницу 1, 2, 3, 4  След.
 
 Задача на C#, не проходит по требуемому времени
Сообщение30.05.2019, 10:15 


03/09/13
49
Есть следующая задача:
Код:
Программисту-фрилансеру Васе Пупкину требуется выполнить n заданий за n дней. У каждого задания известен свой дедлайн, а также его стоимость(то есть, если он не выполняет задание в указанное время, то его работа не оплачивается). Вася настолько крут, что за один день может сделать одно задание. Выполнение задания можно начать с момента 0. Ваша задача определить максимальную прибыль Васи.

Пример исходных данных:
Код:
3
60 2
65 2
70 2

Результат:
Код:
135

За два дня Вася успеет решить только две задачи, и он выберет вторую и третью, что даст ему прибыль в 135 единиц.
Эту задачу нужно решить на C# с использованием жадного алгоритма. Мое решение приведено ниже. Вывод времени добавлен с целью контролировать, сколько работает программа, он необязателен. Файл читается по байтам тоже для быстроты. Программа работает правильно, и проходит все тесты, кроме последнего, ибо там 100000 исходных данных, а нужно успеть за секунду. Что еще ускорить я не знаю.
Код:
using System;
using System.Collections.Generic;
using System.Text;
using System.IO;

namespace ConsoleApp1
{
    class Program
    {
        static void Main(string[] args)
        {
            var y = new List<Tuple<int, int>>();
            var sset = new List<int>();

            Console.WriteLine(DateTime.Now.ToString("h:mm:ss ffff"));

            FileStream fileStream = new FileStream(@"input.txt", FileMode.Open, FileAccess.Read);
            int num = 0;
            int t = fileStream.ReadByte() - 48;
            while (t >= 0)
            {
                num = 10 * num + t;
                t = fileStream.ReadByte() - 48;
            }

            while (t < 0)
            {
                t = fileStream.ReadByte() - 48;
            }

            for (int i = 0; i < num; i++)
            {
                int newcost = 0;
                int newdeadline = 0;

                while (t >= 0)
                {
                    newcost = 10 * newcost + t;
                    t = fileStream.ReadByte() - 48;
                }

                while (t < 0)
                {
                    t = fileStream.ReadByte() - 48;
                }

                while (t >= 0)
                {
                    newdeadline = 10 * newdeadline + t;
                    t = fileStream.ReadByte() - 48;
                }

                if (i != num - 1)
                {
                    while (t < 0)
                    {
                        t = fileStream.ReadByte() - 48;
                    }
                }

                y.Add(Tuple.Create(-newcost, newdeadline));
                sset.Add(i);
            }
            sset.Add(num);
            sset.Add(num + 1);

            y.Sort(Comparer<Tuple<int, int>>.Default);

            Int64 sum = 0;

            for (int i = 0; i < num; i++)
            {
                int lval = 0;
                int uval = sset.Count - 1;

                while ((uval - lval) != 1)
                {
                    int mid = (int)((lval + uval) / 2);
                    int zuval = sset[mid];
                    if (zuval > y[i].Item2) { uval = mid; } else { lval = mid; }
                }

                int xzuval = sset[lval];

                if (xzuval == 0)
                {
                    sset.RemoveAt(sset.Count - 1);
                }
                else
                {
                    sset.RemoveAt(lval);
                    sum = sum - y[i].Item1;
                }
            }

            Console.WriteLine(DateTime.Now.ToString("h:mm:ss ffff"));

            StreamWriter sw = new StreamWriter(@"output.txt");
            sw.WriteLine(sum);
            sw.Close();
        }
    }
}


-- 30.05.2019, 13:17 --

И еще - если на C# быстрее не получится, можно на C++, если будет быстрее, но там я вообще не представляю как.

 Профиль  
                  
 
 Re: Задача на C#, не проходит по требуемому времени
Сообщение30.05.2019, 11:39 
Заслуженный участник
Аватара пользователя


30/01/06
72407
Как по-вашему, какова алгоритмическая сложность вашего решения? $\mathcal{O}(n)$? $\mathcal{O}(n\log n)$? $\mathcal{O}(n^2)$? Другая?
Почему?

 Профиль  
                  
 
 Re: Задача на C#, не проходит по требуемому времени
Сообщение30.05.2019, 15:10 


03/09/13
49
Квадратичная, так как есть цикл по всем работам, и внутри есть удаление элемента из списка. Списки в C# это обертки над массивами (а не над двусвязными списками). Так что n*n -> n^2.
Я пробовал заменить массив на LinkedList, но мне нужно обращаться к нему по индексу. Можно в принципе использовать set, но с ним у меня почему-то получилось еще медленнее.

 Профиль  
                  
 
 Re: Задача на C#, не проходит по требуемому времени
Сообщение30.05.2019, 15:13 
Заслуженный участник
Аватара пользователя


30/01/06
72407
А может быть, можно сделать алгоритм так, чтобы не удалять элементы из списка?

Намёк: сначала вы зачем-то сортируете (другой) массив. Время сортировки $\mathcal{O}(n\log n),$ кстати говоря.

 Профиль  
                  
 
 Re: Задача на C#, не проходит по требуемому времени
Сообщение30.05.2019, 15:22 


03/09/13
49
Я сортирую другой массив, который содержит дедлайны и стоимость. Так как я использую жадный алгоритм, то мне нужны сначала самые дорогие работы. Это - да, $n\cdot\log(n)$
Но потом, когда я беру самую дорогую работу, и вижу, что ее нужно сделать, например до дня №7, мне нужно отметить, что мой день №6 теперь занят. Для этого я удаляю из второго массива, в котором просто числа от 1 до N (количества работ) нужное число.

 Профиль  
                  
 
 Re: Задача на C#, не проходит по требуемому времени
Сообщение30.05.2019, 15:25 
Заслуженный участник
Аватара пользователя


30/01/06
72407
Ну и переделайте алгоритм так, чтобы он не требовал заполнения дней в беспорядке.

 Профиль  
                  
 
 Re: Задача на C#, не проходит по требуемому времени
Сообщение30.05.2019, 15:26 


03/09/13
49
В этом и весь вопрос. Я могу придумать только такой алгоритм. Если заполнять дни по очереди, то возможно мы получим не самые дорогие работы.

 Профиль  
                  
 
 Re: Задача на C#, не проходит по требуемому времени
Сообщение30.05.2019, 15:29 
Заслуженный участник
Аватара пользователя


30/01/06
72407
blueboar2 в сообщении #1396612 писал(а):
Если заполнять дни по очереди, то возможно мы получим не самые дорогие работы.

Объясните поподробней.

 Профиль  
                  
 
 Re: Задача на C#, не проходит по требуемому времени
Сообщение30.05.2019, 15:33 


03/09/13
49
Ну например, у нас десять работ. Первая стоимостью 2 рубля, должна быть сделана в первый день. Восемь работ стоимостью 100 единиц, до пятого дня, и одна, 2 рубля, до десятого. Если мы отсортируем массив по дедлайну по возрастанию, то получим сначала первую работу, потом 2-9, потом десятую. Возьмем первую в первый день, вторую во второй, третью в третий, четвертую в четвертый, пятую в пятый. Дальше десятую в любой после этого. Итого 404 рубля.

Но мы могли бы взять вторую в первый день, третью во второй, четвертую в третий, пятую в четвертый, шестую в пятый, десятую скажем в шестой. Получим 502 рубля, что есть лучше.

 Профиль  
                  
 
 Re: Задача на C#, не проходит по требуемому времени
Сообщение30.05.2019, 15:56 
Заслуженный участник
Аватара пользователя


30/01/06
72407
blueboar2 в сообщении #1396617 писал(а):
Если мы отсортируем массив по дедлайну по возрастанию

...а если как-то иначе?

-- 30.05.2019 15:57:31 --

Вот например, по стоимости вы сортируете по убыванию.

 Профиль  
                  
 
 Re: Задача на C#, не проходит по требуемому времени
Сообщение30.05.2019, 16:27 


03/09/13
49
Хорошо, я вас понял, кажется. Я правильно понимаю, что если бы дней было n, а работ 2n, то этот алгоритм не сработал бы?

 Профиль  
                  
 
 Re: Задача на C#, не проходит по требуемому времени
Сообщение30.05.2019, 17:07 
Заслуженный участник
Аватара пользователя


30/01/06
72407
Ну, это уже не знаю.

 Профиль  
                  
 
 Re: Задача на C#, не проходит по требуемому времени
Сообщение30.05.2019, 18:10 
Заслуженный участник
Аватара пользователя


16/07/14
8458
Цюрих
blueboar2 в сообщении #1396639 писал(а):
Я правильно понимаю, что если бы дней было n, а работ 2n, то этот алгоритм не сработал бы?
Какой алгоритм-то?

Вообще полезно оценивать асимптотику работы и сопоставлять её с размером входа. Если время работы $O(n^2)$, то на входе размера $10^5$ по времени почти наверняка не пройдёт, надо быстрее.

Ваш алгоритм можно улучшить, если заменить sset на что-то, поддерживающее поиск максимального элемента, меньшего данного, и удаление элемента за логарифм (в C++ это умеет std::set, не знаю, есть ли аналоги в C#). А можно полностью переделать - тоже понадобится некоторая нетривиальная структура данных, но гораздо более простая, чем деревья.

 Профиль  
                  
 
 Re: Задача на C#, не проходит по требуемому времени
Сообщение30.05.2019, 18:27 
Экс-модератор
Аватара пользователя


23/12/05
12047

(Оффтоп)

blueboar2 в сообщении #1396541 писал(а):
Вася настолько крут, что за один день может сделать одно задание.
blueboar2 в сообщении #1396541 писал(а):
ибо там 100000 исходных данных
А Вася и правда крут - 270 лет работать без выходных не каждый сможет.


-- Thu May 30, 2019 17:31:43 --

Значения дедлайнов целочисленны и не так уж велики ($100000$ - вполне терпимая длина массива), так что по дедлайну можно отсортировать за $\mathcal{O}(n)$

 Профиль  
                  
 
 Re: Задача на C#, не проходит по требуемому времени
Сообщение30.05.2019, 20:16 


05/09/12
2587
Что-нибудь типа такого

Используется синтаксис Haskell
import Data.List

rp :: String -> (Int, Int)
rp = (\[x,y] -> (- read x, read y)) . words

main = getContents >>= print . fst . foldl' (\(s,i) (a,d) -> if i>=d then (s,i) else (s-a, i+1)) (0,0) . sort . map rp . tail . lines
 

Жаль не гуглится сайт с задачкой (хотя всякие Хабры и Ленты с матроидами гуглятся отлично), не могу проверить на реальных тестах

 Профиль  
                  
Показать сообщения за:  Поле сортировки  
Начать новую тему Ответить на тему  [ Сообщений: 52 ]  На страницу 1, 2, 3, 4  След.

Модераторы: Karan, Toucan, PAV, maxal, Супермодераторы



Кто сейчас на конференции

Сейчас этот форум просматривают: нет зарегистрированных пользователей


Вы не можете начинать темы
Вы не можете отвечать на сообщения
Вы не можете редактировать свои сообщения
Вы не можете удалять свои сообщения
Вы не можете добавлять вложения

Найти:
Powered by phpBB © 2000, 2002, 2005, 2007 phpBB Group