Версия для печати темы
Нажмите сюда для просмотра этой темы в оригинальном формате
Форум программистов > Центр помощи > [Delphi] Задача ЕГЭ С4


Автор: Lacoste1024 6.6.2012, 21:32
Доброе время суток. Возник вопрос при решении задачи. Суть в том, чтобы из набора чисел отобрать минимальную пару чётных чисел, а если такой нет, то просто минимальную пару. У меня за эту задачу 1 из 4х баллов. Своё решение выкладывать пока не буду т.к. хочу узнать ваши методы решения этой задчи.
Формат входных данных: в первой строке - N - количество чисел, далее в каждой строке идёт N числел от 0 до 30000.
Выходные данные: минимальная сумма указанная в условии

P.S. Задачу решить нужно наиболее оптимальным способом как по памяти, так и по времени

Автор: iff 6.6.2012, 21:37
Цитата(Lacoste1024 @  6.6.2012,  21:32 Найти цитируемый пост)
минимальную пару 

Или минимальное произведение?

Автор: Lacoste1024 6.6.2012, 21:51
iff, Минимальную пару, т.е. сумму
P.S. Задачу решить нужно наиболее оптимальным способом как по памяти, так и по времени

Автор: Qu1nt 6.6.2012, 23:43
Особо не тестировал, но суть такая:
Код

program ProblemC4;

{$APPTYPE CONSOLE}

procedure Solve;

  procedure CompareAndUpdate(Value: SmallInt; var MinFirst, MinSecond: SmallInt);
  begin
    if Value < MinFirst then
    begin
       MinSecond := MinFirst;
       MinFirst := Value;
    end
    else if Value < MinSecond then
      MinSecond := Value;
  end;

const
  MaxValue = High(SmallInt);
var
  Count, I: Integer;
  Current, MinFirst, MinSecond, MinOddFirst, MinOddSecond: SmallInt;
  FindOddPair: Boolean;
begin
  MinFirst := MaxValue;
  MinSecond := MaxValue;
  MinOddFirst := MaxValue;
  MinOddSecond := MaxValue;
  FindOddPair := False;

  ReadLn(Count);
  for I := 0 to Count - 1 do
  begin
    ReadLn(Current);
    if Odd(Current) then
    begin
      CompareAndUpdate(Current, MinOddFirst, MinOddSecond);
      if not FindOddPair then
        FindOddPair := (MinOddFirst <> MaxValue) and (MinOddSecond <> MaxValue);
    end;

    if not FindOddPair then
      CompareAndUpdate(Current, MinFirst, MinSecond);
  end;

  if FindOddPair then
    Count := MinOddFirst + MinOddSecond
  else
    Count := MinFirst + MinSecond;

  WriteLn(Count);
end;

begin
  Solve;
end.

Автор: northener 7.6.2012, 01:02
А ЕГЭ по информатике разве уже был?
Сегодня только ночь 7-го июня.

Автор: Lacoste1024 7.6.2012, 05:47
28 мая был. Я решил задачу таким же алгоритмом как Qu1nt. Какие будут ещё версии решения?

Автор: MetalFan 7.6.2012, 07:39
Для домашних заданий, курсовых, существует "Центр Помощи".

Тема перенесена! 

Автор: Qu1nt 7.6.2012, 09:40
Lacoste1024, когда в таких задачах просят использовать наименьшее количество памяти — по сути это отказ от массива. У меня его нет. Единственное, что можно сделать — избавиться от переменной I. А это уже смешно.
Когда подобные задачи просят решить за минимальное время, это значит, что сложность алгоритма должна быть O(n). У меня так. Уменьшить количество сравнений? Какая-то экономия на спичках.
Когда за решение задачи ставят 1/4 — это значит, что задача решена не полностью, ну или человек, который её оценивал не до конца с ним разобрался smile Соответственно, о каких-то баллах за оптимальность речь не идет.

Автор: Lacoste1024 7.6.2012, 13:27
Qu1nt, спасибо большое!

Автор: Lacoste1024 7.6.2012, 19:44
Qu1nt, я задачу решил таким же алгоритмом. Сначала отбор 4х чисел, а затем выбор. 

Получается, у меня правильное решение, однако стоит 1 балл из 4х. Может ли кто-нибудь предложить ещё свои варианты?

Автор: Amphiluke 7.6.2012, 23:28
Еще возможный вариант. Использует немного меньше переменных (в том числе за счет избавления от цикла со счетчиком, о чем говорил Qu1nt). По производительности вряд ли быстрее, но логика, пожалуй, чуть запутаннее   smile   (сопроводил код комментами на всякий).

Код

program FindMinOddPair;

{$APPTYPE CONSOLE}

  procedure Solve;
  var
    N: Integer;
    Min, NextMin, FirstEven, Curr: Word;
  begin
    Min := High(Word);
    if Min mod 2 = 0 then Dec(Min); // put an odd number initially
    NextMin := Min;
    FirstEven := 1; // put an odd number initially
    Readln(N);
    while N > 0 do
    begin
      Readln(Curr);
      if (Min mod 2 = NextMin mod 2) and (Min mod 2 = Curr mod 2) then
      begin // Min, NextMin and Curr are all either odd or even
        if Curr < Min then // Let Min always be less than or equal to NextMin
          Min := Curr
        else if Curr < NextMin then
          NextMin := Curr;
      end
      else
        if Curr mod 2 = 0 then // Both Min and NextMin are odd, and Curr is even
          if FirstEven = 1 then
            FirstEven := Curr // Store the first even number detected
          else
            if FirstEven < Curr then // Let Min always be less than or equal to NextMin
            begin
              Min := FirstEven;
              NextMin := Curr;
            end
            else
            begin
              Min := Curr;
              NextMin := FirstEven;
            end;
      Dec(N);
    end;
    Writeln(Min, ' + ', NextMin, ' = ', Min + NextMin);
  end;

begin

  Solve();
  Readln;

end.

Автор: Qu1nt 8.6.2012, 12:02
Amphiluke, проверять чётность числа через деление — моветон. Только Odd, только хардкор!

Автор: Amphiluke 8.6.2012, 12:22
Qu1nt, экономия на переходах.  smile 
недооценил компилятор.

Автор: Amphiluke 8.6.2012, 12:50
Qu1nt, кстати, что в вашем примере, что в моем есть несоответствие условию задачи (если я правильно понял)


Цитата(Lacoste1024 @  7.6.2012,  01:32 Найти цитируемый пост)
из набора чисел отобрать минимальную пару чётных чисел, а если такой нет, то просто минимальную пару


К примеру, на таком наборе введенных данных
Код

0
1
3
5
7

наши примеры выдадут ответ 1 + 3 = 4
А должно быть 0 + 1 = 1.  smile 
Следовательно, надо перед выдачей ответа ставить дополнительную проверку на случай, когда есть только одно четное число в наборе, и оно меньше одного из найденных (или обоих) наименьших нечетных.


Приложу свой исправленный вариант:
Код

program FindMinOddPair;

{$APPTYPE CONSOLE}

  procedure Solve;
  var
    N: Integer;
    Min, NextMin, FirstEven, Curr: Word;
  begin
    Min := High(Word);
    if not Odd(Min) then Dec(Min); // put an odd number initially
    NextMin := Min;
    FirstEven := 1; // put an odd number initially
    Readln(N);
    while N > 0 do
    begin
      Readln(Curr);
      if (Odd(Min) = Odd(NextMin)) and (Odd(Min) = Odd(Curr)) then
      begin // Min, NextMin and Curr are all either odd or even
        if Curr < Min then // Let Min always be less than or equal to NextMin
          Min := Curr
        else if Curr < NextMin then
          NextMin := Curr;
      end
      else
        if not Odd(Curr) then // Both Min and NextMin are odd, and Curr is even
          if FirstEven = 1 then
            FirstEven := Curr // Store the first even number detected
          else
            if FirstEven < Curr then // Let Min always be less than or equal to NextMin
            begin
              Min := FirstEven;
              NextMin := Curr;
            end
            else
            begin
              Min := Curr;
              NextMin := FirstEven;
            end;
      Dec(N);
    end;

    if Odd(Min) then // Here, both Min and NextMin are of the same parity
      if FirstEven <> 1 then // The only even number in an input set
        if FirstEven < Min then
        begin
          NextMin := Min;
          Min := FirstEven;
        end
        else if FirstEven < NextMin then
          NextMin := FirstEven;

    Writeln(Min, ' + ', NextMin, ' = ', Min + NextMin);
  end;

begin

  Solve();
  Readln;

end.

Автор: Qu1nt 8.6.2012, 15:52
А я искал пару нечетных smile

Powered by Invision Power Board (http://www.invisionboard.com)
© Invision Power Services (http://www.invisionpower.com)