Вот вам небольшая задачка. Я тут встретил,и решение заинтересовала. Кто додумается, напишите: sherifov@ezmail.ru
Есть 6 чисел 9 (a, b, c, d, e, f : integer), которые имеют значения 1, 2, 3, 4, 5, 6, но какое значение какая переменная имеет — не знаем. Мы имеем право "ставить на весы" любые две переменные, то есть мы можем узнать, какое из любых двух чисел больше. Как за минимальное (ну уж не больше 12) таких взвешиваний узнать, какому значению какая переменная соответствует? Нужно решать при помощи Delphi. Спасибо заранее!
Здравствуйте, 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-и элементов.
Здравствуйте, 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 взвешиваний.
Лучший вариант — когда максимум одного массива меньше минимума другого.
Итого — от 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 узлов.
Здравствуйте, Кодт, Вы писали:
К>Здравствуйте, 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 взв.), остальное дерево такое
Философский вопрос: если для сортировки требуется 4.585 сравнения, а у нас
получается 4.667, то какую дополнительную информацию объёмом
4.667 — 4.585 = 0.082 бит мы получаем?
Интересно. что попытавшись сравнивать минимальный элемент первой пары с максимальным
элементом второй пары, в надежде быстрого завершения, среднее количество сравнений
возрастает до 5.17! Халявы не будет!
К>А вот компактное решение с не более чем 11 взвешиваниями — могу предложить.
Всю ночь не спал, думал, а утром оказалось что Кодт уже привёл свой кодт...
...
К> К>Осталась на сладкое интересная задача:
К>построить сбалансированное дерево решений для 6!=720 узлов.
Будем подумать.
Контр задача — вопрос. Будет ли считаться допустимым (не грязным хаком)
производить сравнения "кучками"?
Т.е. сравнивать суммы из нескольких элементов. И даст ли это выигрыш?
Здравствуйте, 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>Т.е. сравнивать суммы из нескольких элементов. И даст ли это выигрыш?
...
M>>Одно сравнение может дать более(!) 1 бита информации. M>>Иначе как объяснить, что для некоторых случаев достаточно 5 сравнений?
К>Ага: за 5 сравнений проверить abcdef==123456
Даже двумя способами!
1)
a ? 1
b ? 2
c ? 3
d ? 4
e ? 5
если все сравнения прошли, то последнее можно не проверять
Т.е. если повезёт, то хватит N-1 сравнение. Но если на это надеятся,
то в среднем выйдет гораздо больше сравнений, чем при оптимальном алгоритме.
К>На самом деле все просто. Берем множество вариантов — строк от 123456 до 654321. К>Для произвольного сравнения, например, a<>b, делим множество на два подкласса (a<b и a>b). Они пока что равномощны, по 360 элементов. К>Для каждого подкласса по отдельности (!) производим еще одно сравнение, делящее его приблизительно поровну... К>На ранних стадиях, в силу симметрии, сравнения у разных ветвей дерева будут совпадать: К>a<>b, c<>d, e<>f... Но далее могут начаться различия.
Здравствуйте, 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 в лучшем.
Насчёт быстрой сортировки я поторопимшись Задача предполагает, что нужно минимизировать число сравнений в наихудшем случае. Поскольку быстрая сортировка в наихудшем случае даёт нам ~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 сравнения.
Здравствуйте, 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>
Не знаю. Можно ли будет разделить класс из 22 конкретных элементов на два равных подкласса по 11 — одним сравнением?
На досуге попробую написать программу, тогда будет видно.