Небольшая задачка-этюд.
От: sherifov  
Дата: 03.05.03 17:03
Оценка: 18 (1) -1
Вот вам небольшая задачка. Я тут встретил,и решение заинтересовала. Кто додумается, напишите: sherifov@ezmail.ru

Есть 6 чисел 9 (a, b, c, d, e, f : integer), которые имеют значения 1, 2, 3, 4, 5, 6, но какое значение какая переменная имеет — не знаем. Мы имеем право "ставить на весы" любые две переменные, то есть мы можем узнать, какое из любых двух чисел больше. Как за минимальное (ну уж не больше 12) таких взвешиваний узнать, какому значению какая переменная соответствует? Нужно решать при помощи Delphi. Спасибо заранее!
Re: Небольшая задачка-этюд.
От: LCR Россия lj://_lcr_
Дата: 04.05.03 10:04
Оценка:
Здравствуйте, sherifov, Вы писали:

S>Вот вам небольшая задачка. Я тут встретил,и решение заинтересовала. Кто додумается, напишите: sherifov@ezmail.ru


S>Есть 6 чисел 9 (a, b, c, d, e, f : integer), которые имеют значения 1, 2, 3, 4, 5, 6, но какое значение какая переменная имеет — не знаем. Мы имеем право "ставить на весы" любые две переменные, то есть мы можем узнать, какое из любых двух чисел больше. Как за минимальное (ну уж не больше 12) таких взвешиваний узнать, какому значению какая переменная соответствует? Нужно решать при помощи Delphi. Спасибо заранее!


Сорри, что замечание не в тему, но алгоритм не имеет никакого отношения к языку или среде програмирования.

Решение.

Эта задача сводится к задаче сортировки массива. Вашу задачу можно переформулировать следующим образом: отсортировать массив, используя наименьшее количество сравнений. И то, что здесь 6 элементов — непринципиально. То есть всё что нужно — это запустить быструю сортировку на массиве из 6-и элементов.

Усё
quicksort =: (($:@(<#[),(=#[),$:@(>#[)) ({~ ?@#)) ^: (1<#)
Re[2]: Небольшая задачка-этюд.
От: Аноним  
Дата: 04.05.03 11:29
Оценка: +1
LCR>То есть всё что нужно — это запустить быструю сортировку на массиве из 6-и элементов.

Почему таким образом минимизируется число сравнений?
Re: Небольшая задачка-этюд.
От: Кодт Россия  
Дата: 04.05.03 12:59
Оценка: 14 (3)
Здравствуйте, sherifov, Вы писали:

S>Есть 6 чисел 9 (a, b, c, d, e, f : integer), которые имеют значения 1, 2, 3, 4, 5, 6, но какое значение какая переменная имеет — не знаем. Мы имеем право "ставить на весы" любые две переменные, то есть мы можем узнать, какое из любых двух чисел больше. Как за минимальное (ну уж не больше 12) таких взвешиваний узнать, какому значению какая переменная соответствует? Нужно решать при помощи Delphi. Спасибо заранее!


Сначала — оценка снизу.
Всего возможны 6! = 720 перестановок.
Каждое сравнение дает 1 бит информации...
log2(720)=9.ххх <= 10, поэтому в среднем потребуется не менее 10 сравнений.

Построение сбалансированного двоичного дерева решений для 720 узлов — задача нетривиальная (хотя именно оно даст минимум).

А вот компактное решение с не более чем 11 взвешиваниями — могу предложить.

1. Сортировка трех чисел — не более 3 взвешиваний
a + b
min(a,b) + c
max(a,b) + c --- если min(a,b)<c

итого от 4 до 6 взвешиваний (две тройки чисел).

2. Сортировка слиянием двух упорядоченных массивов по 3 числа — от 3 до 5 взвешиваний.
Лучший вариант — когда максимум одного массива меньше минимума другого.
            . (1 2 3)  (4 5 6)
1           .   (2 3)  (4 5 6)
1 2         .     (3)  (4 5 6)
1 2 3 4 5 6

Худший вариант — когда числа чередуются.
            . (1 3 5)  (2 4 6)
1           .   (3 5)  (2 4 6)
1 2         .   (3 5)    (4 6)
1 2 3       .     (5)    (4 6)
1 2 3 4     .     (5)      (6)
1 2 3 4 5 6


Итого — от 4+3=7 до 6+5=11.


Как это кодировать на паскале?
Каждый элемент имеет имя ('a'..'f') и значение (1..6).
В результате сортировки элементы не разрушаются.
Вот довольно избыточный код.
type
  name = 'a'..'f';
  value = 1..6;
  element = record
              n:name;
              v:value;
            end;
  elements = array [value] of element;

procedure copy(var dst:element; const src:element)
begin
  dst.n := src.n;
  dst.v := src.v;
end;

function compare(const x:element; const y:element): integer
begin
  compare := x.v - y.v;
end;

procedure swap(var x:element; var y:element)
var z:element;
begin
  copy(z,x); copy(x,y); copy(y,z);
end;

procedure order3(var el:elements; i:value)
begin
  if compare(el[o], el[o+1]) > 0
  then swap(el[o], el[o+1]);

  if compare(el[o+1], el[o+2]) > 0
  then begin
    swap(el[o+1], el[o+2]);

    if compare(el[o], el[o+1]) > 0
    then swap(el[o], el[o+1]);
  end;
end;

procedure order6(var el:elements)
var
  res:elements;
  i,j,k:value;
begin
  order3(el, 1); { a,b,c }
  order3(el, 4); { d,e,f }

  { слияние }
  i := 1; j := 4; k := 1;
  while (i<3) and (j<6) do
  begin
    if compare(el[i], el[j]) < 0
    then begin copy(res[k], el[i]); i:=i+1; end;
    then begin copy(res[k], el[j]); j:=j+1; end;
    k := k+1;
  end;
  { допишем хвосты }
  while i<3 do begin copy(res[k], el[i]); i:=i+1; k:=k+1; end;
  while j<6 do begin copy(res[k], el[j]); j:=j+1; k:=k+1; end;

  { вернем результат в исходный массив }
  for i:=1 to 6 do copy(el[i], res[i]);
end;



Осталась на сладкое интересная задача:

построить сбалансированное дерево решений для 6!=720 узлов.
(=^.^=) Neko ... << RSDN@Home 1.0 beta 6a >>
Перекуём баги на фичи!
Re[2]: Небольшая задачка-этюд.
От: mrhru Россия  
Дата: 05.05.03 02:47
Оценка:
Здравствуйте, Кодт, Вы писали:

К>Здравствуйте, sherifov, Вы писали:


S>>Есть 6 чисел 9 (a, b, c, d, e, f : integer), которые имеют значения 1, 2, 3, 4, 5, 6, но какое значение какая переменная имеет — не знаем. Мы имеем право "ставить на весы" любые две переменные, то есть мы можем узнать, какое из любых двух чисел больше. Как за минимальное (ну уж не больше 12) таких взвешиваний узнать, какому значению какая переменная соответствует? Нужно решать при помощи Delphi. Спасибо заранее!


Кстати, почему 12, а не 15? Попарное сравнение всего со всем даёт 6 * 5 / 2 = 15.

К>Сначала — оценка снизу.

К>Всего возможны 6! = 720 перестановок.
К>Каждое сравнение дает 1 бит информации...
К>log2(720)=9.ххх <= 10, поэтому в среднем потребуется не менее 10 сравнений.

log2(720)=9.49xxx, поэтому в среднем потребуется 9.5 сравнений.

Одно сравнение может дать более(!) 1 бита информации.
Иначе как объяснить, что для некоторых случаев достаточно 5 сравнений?
1) Сортируем пары (a1<a2)(b1<b2)(c1<c2) (3 сравнения)
2) Сравниваем a2<b1 и b2<c1 (2 сравнения)

Итого, почти 2 бита на сравнение.

Точнее говоря, результаты некоторых взвешиваний не симметричны.

К>Построение сбалансированного двоичного дерева решений для 720 узлов — задача нетривиальная (хотя именно оно даст минимум).


Можно потренироваться на кошках , если рассмотреть не 6 а 4 взвешивания.
Оценка взвешиваний. 4! = 24; log2(24) = 4.585
Предварительно отсортировав пары (a1<a2) (b1<b2) (2 взв.), остальное дерево такое
                   a1 ? b1
                   </   \>
                   /     \
                  /       \
                 /         \
          a2 ? b2           a2 ? b2
          </  \>            </   \>
          /  a1b1b2a2  b1a1a2b2   \
       a2 ? b1                  a1 ? b2
       </   \>                  </   \>
a1a2b1b2     a1b1a2b2    b1a1b2a2     b1b2a1a2


Количество сравнений 2 + 1 + 1/3 * 1 + 2/3 * 2 = 4.667

Философский вопрос: если для сортировки требуется 4.585 сравнения, а у нас
получается 4.667, то какую дополнительную информацию объёмом
4.667 — 4.585 = 0.082 бит мы получаем?

Интересно. что попытавшись сравнивать минимальный элемент первой пары с максимальным
элементом второй пары, в надежде быстрого завершения, среднее количество сравнений
возрастает до 5.17! Халявы не будет!

К>А вот компактное решение с не более чем 11 взвешиваниями — могу предложить.


Всю ночь не спал, думал, а утром оказалось что Кодт уже привёл свой кодт...

...

К>

К>Осталась на сладкое интересная задача:

К>построить сбалансированное дерево решений для 6!=720 узлов.


Будем подумать.

Контр задача — вопрос. Будет ли считаться допустимым (не грязным хаком)
производить сравнения "кучками"?
Т.е. сравнивать суммы из нескольких элементов. И даст ли это выигрыш?
Re[3]: Небольшая задачка-этюд.
От: Кодт Россия  
Дата: 05.05.03 06:24
Оценка:
Здравствуйте, mrhru, Вы писали:

M>Кстати, почему 12, а не 15? Попарное сравнение всего со всем даёт 6 * 5 / 2 = 15.


Видимо, потому что автору задачи известно решение для 12 сравнений

К>>Сначала — оценка снизу.

К>>Всего возможны 6! = 720 перестановок.
К>>Каждое сравнение дает 1 бит информации...
К>>log2(720)=9.ххх <= 10, поэтому в среднем потребуется не менее 10 сравнений.

M>log2(720)=9.49xxx, поэтому в среднем потребуется 9.5 сравнений.


Я имел в виду — для любого заданного алгоритма (который может быть и неоптимальным).
9.5 — это нижняя граница среднего времени работы.

M>Одно сравнение может дать более(!) 1 бита информации.

M>Иначе как объяснить, что для некоторых случаев достаточно 5 сравнений?

Ага: за 5 сравнений проверить abcdef==123456

Можно предположить иное: алгоритм не считает события равновероятными. (Жизнь, конечно, его разочарует — но ничего не поделаешь). Соответственно, 12345 несет 5 бит, а 654321 — 15 бит (для сортировки пузырьком). Вероятности их P = 2^(-I) где I — информативность.

К>>А вот компактное решение с не более чем 11 взвешиваниями — могу предложить.


M>Всю ночь не спал, думал, а утром оказалось что Кодт уже привёл свой кодт...


Оно не обязательно единственное.
Например, отсортировав 4 числа (за 4-5 сравнений) твоим способом, вставить в него оставшиеся 2 числа за (2-3 + 3). Итого тоже 11.

К>>

К>>Осталась на сладкое интересная задача:

К>>построить сбалансированное дерево решений для 6!=720 узлов.


M>Будем подумать.


На самом деле все просто. Берем множество вариантов — строк от 123456 до 654321.
Для произвольного сравнения, например, a<>b, делим множество на два подкласса (a<b и a>b). Они пока что равномощны, по 360 элементов.
Для каждого подкласса по отдельности (!) производим еще одно сравнение, делящее его приблизительно поровну...
На ранних стадиях, в силу симметрии, сравнения у разных ветвей дерева будут совпадать:
a<>b, c<>d, e<>f... Но далее могут начаться различия.

M>Контр задача — вопрос. Будет ли считаться допустимым (не грязным хаком)

M>производить сравнения "кучками"?
M>Т.е. сравнивать суммы из нескольких элементов. И даст ли это выигрыш?

Тоже будем подумать.
(=^.^=) Neko ... << RSDN@Home 1.0 beta 6a >>
Перекуём баги на фичи!
Re[4]: Небольшая задачка-этюд.
От: mrhru Россия  
Дата: 05.05.03 07:10
Оценка:
Здравствуйте, Кодт, Вы писали:

...

M>>Одно сравнение может дать более(!) 1 бита информации.

M>>Иначе как объяснить, что для некоторых случаев достаточно 5 сравнений?

К>Ага: за 5 сравнений проверить abcdef==123456


Даже двумя способами!
1)
a ? 1
b ? 2
c ? 3
d ? 4
e ? 5
если все сравнения прошли, то последнее можно не проверять

2) Сравниваем пары a<b, c<d, e<f (3 срв.)
Сравниваем концы цепочек b<c, d<e (2 срв.)

Т.е. если повезёт, то хватит N-1 сравнение. Но если на это надеятся,
то в среднем выйдет гораздо больше сравнений, чем при оптимальном алгоритме.

К>На самом деле все просто. Берем множество вариантов — строк от 123456 до 654321.

К>Для произвольного сравнения, например, a<>b, делим множество на два подкласса (a<b и a>b). Они пока что равномощны, по 360 элементов.
К>Для каждого подкласса по отдельности (!) производим еще одно сравнение, делящее его приблизительно поровну...
К>На ранних стадиях, в силу симметрии, сравнения у разных ветвей дерева будут совпадать:
К>a<>b, c<>d, e<>f... Но далее могут начаться различия.

Так?
              360 (одинаковые не не пишем)
              180                      
               90                      
               45                      
        22             23              
     11            11        12
   5    6        5    6         6
 2   3    3    2   3    3    3    3
 1  2 1  2 1   1  2 1  2 1  2 1  2 1
Re: 10 сравнений
От: MichaelP  
Дата: 05.05.03 08:13
Оценка: 34 (3)
Здравствуйте, sherifov, Вы писали:

S>Вот вам небольшая задачка. Я тут встретил,и решение заинтересовала. Кто додумается, напишите: sherifov@ezmail.ru


S>Есть 6 чисел 9 (a, b, c, d, e, f : integer), которые имеют значения 1, 2, 3, 4, 5, 6, но какое значение какая переменная имеет — не знаем. Мы имеем право "ставить на весы" любые две переменные, то есть мы можем узнать, какое из любых двух чисел больше. Как за минимальное (ну уж не больше 12) таких взвешиваний узнать, какому значению какая переменная соответствует? Нужно решать при помощи Delphi. Спасибо заранее!



1. Разбиваем на пары, сортируем каждую пару — 3 сравнения
2. Сортируем наибольшие эл-ты в каждой паре, паралелльно с наибольшими преставляя наименьшие — 3 сравнения
В итоге имеем два массива:
a1 <= a2 <= a3 и b1 <= a1, b2 <= a2, b3 <= a3

3. Добавляем b1 в начало массива a1...a3.
4. Вставляем b3 в массив b1, a1, a2 — 2 сравнения
5. Вставляем b2 в массив (b1 или b3)...(b3 или a1) — 2 сравнения в худшем случае, 1 в лучшем.

Итого: 10 сравнений.

К сожалению, в отличии от решения Кодта
Автор: Кодт
Дата: 04.05.03
этот алгоритм в лучшем случае требует 9-и сравнений.
Re[3]: Небольшая задачка-этюд.
От: LCR Россия lj://_lcr_
Дата: 05.05.03 08:16
Оценка:
Здравствуйте, mrhru:

M>Здравствуйте, Кодт:


Насчёт быстрой сортировки я поторопимшись Задача предполагает, что нужно минимизировать число сравнений в наихудшем случае. Поскольку быстрая сортировка в наихудшем случае даёт нам ~n^2, то это не то, что нам нужно.

M>Контр задача — вопрос. Будет ли считаться допустимым (не грязным хаком)

M>производить сравнения "кучками"?
M>Т.е. сравнивать суммы из нескольких элементов. И даст ли это выигрыш?

Можно снова потренироваться на 4-х элементах: a, b, c, d; До строгого доказательства далеко, но есть некоторые свидетельства в пользу того, что это не даст выигрыша. А именно: перед началом каких либо тестов у нас есть 24=4! возможных перестановки элементов {a,b,c,d}. Любое сравнение вида a ? b уменьшает количество возможных перестановок ровно наполовину. Сравнение же вида a+b ? c+d ничего не уменьшает.

Второе свидетельство в пользу моего тезиса: предположим, что нам нужно упорядочить числа, причём можно использовать только сравнения сумм, и один и тот же член не может быть в разных частях сравнения, то есть для нашего случая можно пользоваться только следующими сравнениями:
a+b ? c+d
a+c ? b+d
a+d ? b+c

Не ограничивая общности можно считать, что мы получили
a+b < c+d
a+c < b+d
a+d < b+c

Отсюда мы можем заключить лишь то, что
a < c; a < b; a < d; a < b+c+d;

Эти условия сокращают перечень возможных перестановок до
abcd; abdc; acbd; acdb; adbc; adcb;

и чтобы упорядочить элементы b,c,d нам нужно ещё 3 сравнения.

Вот.
quicksort =: (($:@(<#[),(=#[),$:@(>#[)) ({~ ?@#)) ^: (1<#)
Re[5]: Небольшая задачка-этюд.
От: Кодт Россия  
Дата: 05.05.03 09:06
Оценка:
Здравствуйте, mrhru, Вы писали:

К>>Ага: за 5 сравнений проверить abcdef==123456


M>Даже двумя способами!

M>1)
M> a ? 1
M> b ? 2
M> c ? 3
M> d ? 4
M> e ? 5
M>если все сравнения прошли, то последнее можно не проверять

Это хак. У нас нет эталонных монеток 1..5.

M>2) Сравниваем пары a<b, c<d, e<f (3 срв.)

M> Сравниваем концы цепочек b<c, d<e (2 срв.)

Даже еще проще.
if(a<b)
  if(b<c)
    if(c<d)
      if(d<e)
        if(e<f)
          cout << "abcdef"; // вот оно
        else
          cout << "abcdfe"; // ну, это тоже понятно
      else
         // а вот здесь придется попариться.


M>Т.е. если повезёт, то хватит N-1 сравнение. Но если на это надеятся,

M>то в среднем выйдет гораздо больше сравнений, чем при оптимальном алгоритме.

Кто бы спорил

К>>На самом деле все просто. Берем множество вариантов — строк от 123456 до 654321.

К>>Для произвольного сравнения, например, a<>b, делим множество на два подкласса (a<b и a>b). Они пока что равномощны, по 360 элементов.
К>>Для каждого подкласса по отдельности (!) производим еще одно сравнение, делящее его приблизительно поровну...
К>>На ранних стадиях, в силу симметрии, сравнения у разных ветвей дерева будут совпадать:
К>>a<>b, c<>d, e<>f... Но далее могут начаться различия.

M>Так?

M>
M>              360 (одинаковые не не пишем)
M>              180                      
M>               90                      
M>               45                      
M>        22             23              
M>     11            11        12
M>   5    6        5    6         6
M> 2   3    3    2   3    3    3    3
M> 1  2 1  2 1   1  2 1  2 1  2 1  2 1
M>


Не знаю. Можно ли будет разделить класс из 22 конкретных элементов на два равных подкласса по 11 — одним сравнением?
На досуге попробую написать программу, тогда будет видно.
(=^.^=) Neko ... << RSDN@Home 1.0 beta 6a >>
Перекуём баги на фичи!
 
Подождите ...
Wait...
Пока на собственное сообщение не было ответов, его можно удалить.