Форум программистов
 

Восстановите пароль или Зарегистрируйтесь на форуме, о проблемах и с заказом рекламы пишите сюда - alarforum@yandex.ru, проверяйте папку спам!

Вернуться   Форум программистов > IT форум > Помощь студентам
Регистрация

Восстановить пароль
Повторная активизация e-mail

Купить рекламу на форуме - 42 тыс руб за месяц

Ответ
 
Опции темы Поиск в этой теме
Старый 16.11.2011, 13:44   #1
whatever
a.k.a. Skull
Форумчанин
 
Регистрация: 17.11.2009
Сообщений: 963
По умолчанию Требуется алгоритм упаковки последовательности (задача про матрёшки)

День добрый.

Задание:
Коллекцию из N матрешек нужно перевезти на далекое расстояние. Для этого их нужно упаковать, чтобы они занимали как можно меньше места и при этом не гремели. Каждая из матрешек характеризуется своим размером, который задается натуральным числом. Среди них могут быть матрешки одинакового размера. Вы можете их вставлять друг в друга по такому правилу: если первая матрешка имеет размер L, то она может быть вставлена в матрешку размера L+1. Вложенность может быть сколь угодно большой. Например, если вы имеете три матрешки размера 10, 11 и 12, то можете сделать из них одну размера 12, положив первую во вторую, а затем вторую (с первой внутри) в третью. А если же у вас в наличии матрешки размера 10, 20 и 21, то из них можно получить только две упакованные матрешки. Ваша задача узнать, какое минимальное количество матрешек можно получить.

Входные данные
В первой строке входного файла задано целое число N (0 < N ≤ 10^5). В следующей строке через пробел записаны N натуральных чисел, каждое из которых не превышает 10^9— размеры матрешек.

Выходные данные
В выходной файл необходимо вывести одно целое число — минимальное количество упакованных матрешек.


В общем не долго думая решаю:
Код:
program Project1;
{$APPTYPE CONSOLE}
uses
  SysUtils;

type
  Mass=array of integer;
var
  T:textfile;
  i,j,k,n:integer;
  m:mass;
begin
  if fileexists('input.txt') then
    begin
      assignfile(T,'input.txt');
      reset(T);
      readln(T,i);
      setlength(m,i);
      i:=0;
      while not EOF(T) do
        begin
          read(T,m[i]);
          i:=i+1;
        end;
      close(T);
      for i:=high(m)-1 downto 0 do
        for j:=0 to i do
          if m[j]>m[j + 1] then
            begin
              n:=m[j];
              m[j]:=m[j+1];
              m[j+1]:=n;
            end;
      //Есть отсортированный массив
      n:=1;
      for i:=0 to high(m)-1 do
        if m[i+1]-m[i]<>1 then n:=n+1;

//      for i:=0 to high(m) do write(m[i],' ');
      assignfile(T,'output.txt');
      rewrite(T);
      write(T,n);
      close(T);
    end
  else
    begin
      writeln('input.txt not found');
      readln
    end;
end.
Затем пишу прогу для создания input.txt:
Код:
program Project1;
{$APPTYPE CONSOLE}
uses
  SysUtils;
type
  mass=array of integer;
var
  T:textfile;
  i,n:integer;
  m:mass;
begin
randomize;
assignfile(T,'input.txt');
rewrite(T);
readln(n);
writeln(T,n);
for i:=0 to n do write(T,1+random(1000000000),' ');
close(T);
end.
Собственно проблема в том, что если в инпуте 100000 (максимум) значений, программа думает очень долго, а в требованяих "Максимальное время работы на одном тесте: 1 секунда". Как я понял, происходит это из-за сортировки.

В общем нужен другой алгоритм решения, просто на словах, писать программу за меня не надо (я понимаю, что никто и так не стал бы, но все таки :D)
Все тривиальное просто
whatever вне форума Ответить с цитированием
Старый 16.11.2011, 14:01   #2
veniside
Старожил
 
Регистрация: 03.01.2011
Сообщений: 2,508
По умолчанию

Сортировку можно пофиксить, методов дофига, но проблема не в этом. Основная проблема вот тут:

Код:
n:=1;
for i:=0 to high(m)-1 do
  if m[i+1]-m[i]<>1 then n:=n+1;
Какое будет n для отсортированного массива m = (1, 1, 1, 2, 2, 2, 3, 3, 3)? Примерно 7.
А должно быть какое? Правильно, должно быть 3.
"Когда приходит положенное время, человек перестаёт играть в пинбол. Только и всего."
veniside вне форума Ответить с цитированием
Старый 16.11.2011, 14:01   #3
Вадим Мошев

Старожил
 
Аватар для Вадим Мошев
 
Регистрация: 12.11.2010
Сообщений: 8,568
По умолчанию

Ну, могу предложить вот что.
В массиве посчитать количество последовательностей, таких, что при их упорядочивании соседние её члены отличаются на 1. Оно и будет равно минимальном количеству матрёшек.
Вадим Мошев вне форума Ответить с цитированием
Старый 16.11.2011, 14:37   #4
whatever
a.k.a. Skull
Форумчанин
 
Регистрация: 17.11.2009
Сообщений: 963
По умолчанию

veniside, спасибо, поправил:
Код:
program Project1;
{$APPTYPE CONSOLE}
uses
  SysUtils;

type
  Mass=array of integer;

function count(m:mass):integer;
var
  i,k:integer;
  nM:mass;
begin
  result:=1;
  setlength(nM,0);
  k:=0;
  for i:=0 to high(m)-1 do
    begin
      if (m[i+1]-m[i]<>1) and (m[i+1]<>m[i]) then result:=result+1;
      if m[i+1]=m[i] then
        begin
          setlength(nM,length(nM)+1);
          nM[k]:=m[i];
          k:=k+1
        end;
    end;

  if length(nM)<>0 then result:=result+count(nM);
end;


var
  T:textfile;
  i,j,k,n:integer;
  m:mass;
begin
  if fileexists('input.txt') then
    begin
      assignfile(T,'input.txt');
      reset(T);
      readln(T,i);
      setlength(m,i);
      i:=0;
      while not EOF(T) do
        begin
          read(T,m[i]);
          i:=i+1;
        end;
      close(T);
      for i:=high(m)-1 downto 0 do
        for j:=0 to i do
          if m[j]>m[j + 1] then
            begin
              n:=m[j];
              m[j]:=m[j+1];
              m[j+1]:=n;
            end;
      //Есть отсортированный массив

//      for i:=0 to high(m) do write(m[i],' ');
      assignfile(T,'output.txt');
      rewrite(T);
      write(T,count(m));
      close(T);
    end
  else
    begin
      writeln('input.txt not found');
      readln
    end;
end.
Теперь вроде бы верно, но опять же рекурсия, штука тормозная, для 1,1,1,1....1 могу горя хапнуть. Пойду по сслыке, искать сортировку пошустрее. Если у кого-нибудь есть другие идеи, пожалуйста, делитесь

Вадим Мошев, то, что ты предлагаешь, тоже требует множество пробежек по массиву для составления этих последовательностей, а потом еще и сортировки... Врядли это будет работать быстрее. Либо я что-то не так понял.
Все тривиальное просто
whatever вне форума Ответить с цитированием
Старый 16.11.2011, 14:51   #5
Вадим Мошев

Старожил
 
Аватар для Вадим Мошев
 
Регистрация: 12.11.2010
Сообщений: 8,568
По умолчанию

Ну, сначала сортировка (рекомендую Быструю или сортировку Шелла), а потом мой алгоритм.
Вадим Мошев вне форума Ответить с цитированием
Старый 16.11.2011, 15:07   #6
whatever
a.k.a. Skull
Форумчанин
 
Регистрация: 17.11.2009
Сообщений: 963
По умолчанию

Ахр*неть, нет слов. Очень быстрая сортировка, спасибо, Вадим. Странно, что про нее в универе не рассказывали. Осталось понять, как она работает, но тут я как-нибудь сам :D. Сейчас попробую избавиться от рекурсии и посчитать последовательности, как ты советовал.
Все тривиальное просто
whatever вне форума Ответить с цитированием
Старый 16.11.2011, 15:16   #7
mMAg
Форумчанин
 
Аватар для mMAg
 
Регистрация: 11.08.2009
Сообщений: 433
По умолчанию

Ну, для того чтобы отработало за 1 сек, нельзя использовать алгоритм, сложнее чем n*log(n)^k, это очевидно.
сортировку вы, допустим, сделаете слиянием или быструю (но у этой в худшем случае тоже сложность n^2, так что при наличии нужного теста вы тоже запоретесь), но вот далее рекурсия ваша... мне просто лень углубляться в ваш код, если бы на словах объяснили..

Вот пару плохих, требующих доработки мыслей насчет задачи:
вместо прямого решения в лоб, а-ля сортану и найду, рассмотреть сортировку лишь как способ посчитать количество.
как примерно можно было бы решить задачу: создать еще 1 массив, в котором просто проставить значения размеров матрешки, а потом посчитать их количество. далее, обычно, легко придумать, как по такой матрице дать ответ на поставленный в задаче вопрос за линейное время. но вот ограничение на размер 10^9 наводит на мысль о том, что этот способ решения от нас составители старательно спрятали. если хотя бы 10^6...
ладно, возвращаемся к исходным данным. допустим, мы отсортили массив за n*log(n) сортировкой слиянием. далее что? далее помним, что нам нужна "линия". идем по массиву и считаем количество значений. на переходах от одного значения к другому проверяем, рядом ли значения. если да, то какое-то количество матрешек с предыдущего уровня можно упрятать в матрешки следующего. если нет, тогда все матрешки предыдущего добавляются к общему количеству матрешек. далее на текущем уровне считаем количество матрешек. если их больше или равно, чем на предыдущем, тогда все с предыдующего упрячем в текущие, текущие заносим в буфер предыдущих. если меньше, тогда количество предыдущих - количество текущих добавляем к общему количеству матрешек. и так далее.
надеюсь, суть вам ясна, сложность алгоритма n*log(n) на этапе сортировки и n на этапе подсчета, т.е. O(n*log(n) + n) = O(n*log(n)), что вам как раз подойдет.
если что не понятно, я поясню или код напишу, тут на этапе подсчета его кот наплакал.

Кстати, пока писал Вадим Мошев вам весьма дельную мысль подкинул, но он забыл указать, что вам придется посчитать минимальное количество упорядоченных последовательностей, соседние члены которых отличаются на 1, а я вам, считайте, написал как это сделать.

Последний раз редактировалось mMAg; 16.11.2011 в 15:25.
mMAg вне форума Ответить с цитированием
Ответ


Купить рекламу на форуме - 42 тыс руб за месяц



Похожие темы
Тема Автор Раздел Ответов Последнее сообщение
Разработать алгоритм и составить программу для решения задачи. Длину последовательности задать димон4ик_ Помощь студентам 2 18.10.2011 09:39
> Алгоритм последовательности 2an-2–2, где a1=3 и a2=2 turtles Помощь студентам 6 27.09.2011 12:30
Сложнейший алгоритм (сортировка последовательности чисел по группам), программа? язык написания? Владимир777 Помощь студентам 1 02.03.2010 22:15
Сложнейший алгоритм (сортировка последовательности чисел по группам) Владимир777 Фриланс 3 02.03.2010 21:50