Re[2]: Вот вам другая задачка
От: Anonim  
Дата: 11.01.20 13:20
Оценка: +4
Здравствуйте, Bjorn Skalpe, Вы писали:

BS>Есть 1000 бутылок вина, одна бутылка отравлена. Есть 10 крыс. 1 капля вина гарантированно убивает крысу. Крыс можно поить 1 раз в день. За сколько минимально дней можно определить в какой бутылке яд?


BS>upd. Процесс умирания крысы происходит не мгновенно, а за 1 день.


Нумеруем бутылки в двоичной систем получаем 10 битовые числа, а у нас как раз 10 крыс.
Каждой крысе наливаем по капли из всех бутылок где ее бит равен 1.
Соответственно на следующий день, узнаем номер бутылки.
Если сдохли все значит 512 капель хорошего вина убивает крысу.
Re[4]: Задачке 45+ лет.
От: deimos  
Дата: 04.02.20 13:12
Оценка: 12 (1) +1 :)
Здравствуйте, NovaMind, Вы писали:

NM>Я тоже хвастаться люблю!!!


А я никогда не хвастаюсь, потому что гении скромные!
Re[2]: Задачке 45+ лет.
От: Muxa  
Дата: 11.01.20 07:24
Оценка: +2 -1
NM>Мой папа(Царствие ему небесное) рассказывал, что задачка остановила работу военного НИИ по РСМД на неделю...
неделю всем НИИ решали?
придумал решение секунд за 20.
Re[2]: Задачке 45+ лет.
От: namespace  
Дата: 11.01.20 20:34
Оценка: :)))
NM>Мой папа(Царствие ему небесное) рассказывал, что задачка остановила работу военного НИИ по РСМД на неделю...
Только 1% людей могут решить эту задачу! © популярный развлекательный сайт.
Re: Задачке 45+ лет.
От: Erop Россия  
Дата: 26.02.20 17:42
Оценка: 8 (2)
Здравствуйте, NovaMind, Вы писали:


NM>Есть 12 монет.

NM>Одна отличается по весу.
NM>За 3(три) взвешиваня найти эту монету и определить тяжелее она или легче.

NM>Image: Libra2.jpg


Нашлось у меня два-три часика свободного времени у компа сына с питоном на ходу.
Так что попробуем решить грубой силой, а не всякими там рассуждениями на две недели
Ну, поехали.

Разберёмся с порядком перебора.
Нам надо уметь перебирать уникальные наборы монет вида "три монеты из множества против двух монет из того же множества). при этом их стоит перебирать в порядке возрастания суммарного числа элементов множеств, так как чем больше монет в деле, тем, больше шансов, что в этой группе больше наборов.

  "для начала решим более простую задачу: напишем генератор таких пар подмножеств."
Начнём с того, что построим список пар размеров подмножеств.
Можем заметить, что может можно написать и поумнее, но мне лень, тем более, что время работы этого генератора, очевидно, очень маленькое.

def _get_subsets_sizes( max_size, max_diff, max_sum ) :
    """
    Генерируем последовательность размеров пар подмножеств, таких, 
    что бы каждое следующее можно было получить из какого-то предыдущего
    И что бы сначала перебирать группы множеств с меньшей вариативностью. 
    """
    res = set() # будем строить множество, что бы не париться с повторами, хотя мы и строим каждую пару один раз
    for left_size in range(1, max_size+1) : # леове множество всегда не пустое и максимум max_size
        for right_size in range( max(0, left_size-max_diff), min(max_size, left_size+max_diff ) + 1 ) :
            to_add = left_size, right_size
            assert to_add not in res, f"Повторно сгенерировали пару {to_add}" #это для эстетов
            # Мы уже итерируем такие значения right_size, что 0 <= right_size <= max_size
            # И -max_diff <= right_size - max_size <= max_diff
            if sum(to_add) <= max_sum : # Но есть ещё условие на максимальную сумму размеров
                res.add( to_add ) 
    # множество построено, осталось отсортировать.
    return sorted( res, key=lambda x:(sum(x), max(x), x))


  "проверим, что получилось"
print( f"{( 4, 0, 12 )}:", _get_subsets_sizes( 4, 0, 12 ) )
print( f"{( 4, 2, 12 )}:", _get_subsets_sizes( 4, 2, 12 ) )
print( f"{( 4, 4, 12 )}:", _get_subsets_sizes( 4, 4, 12 ) )
Печатает:
(4, 0, 12): [(1, 1), (2, 2), (3, 3), (4, 4)]
(4, 2, 12): [(1, 0), (1, 1), (2, 0), (1, 2), (2, 1), (2, 2), (1, 3), (3, 1), (2, 3), (3, 2), (3, 3), (2, 4), (4, 2), (3, 4), (4, 3), (4, 4)]
(4, 4, 12): [(1, 0), (1, 1), (2, 0), (1, 2), (2, 1), (3, 0), (2, 2), (1, 3), (3, 1), (4, 0), (2, 3), (3, 2), (1, 4), (4, 1), (3, 3), (2, 4), (4, 2), (3, 4), (4, 3), (4, 4)]


Напишем ещё несколько запчастей.
Для того, что бы облегчить себе отсечения множеств, отличающихся только порядком элементов, потребуем, что бы наши элементы были
1) все разными
2) все упорядочены по <
Генерировать будем так.
Будем строить по одному наборы подмножеств одного размера.
При этом запоминать будем не пары подмножеств, а тройки, так как нас интересуют ещё и те элементы, которые ещё можно добавлять.
Кроме того, давайте договоримся, не ограничивая общности, что
1) Пустым может быть только правое множество
2) Самый маленький элемент всегда находится в левом множестве
4) Сами множества будем строить упорядоченными, что бы не получать дубликаты, отличающиеся только порядком элементов. То есть в терминах python'а это будут списки
5) Левое и правое подмножества не могут пересекаться.
6) В целях экономии памяти, третье подмножество (подмножество кандидатов) будем вычислять не каждый раз, а пореже, осуществляя доп. фильтрацию при расширении подмножества

Итак, начнём с функции, которая из набора упорядочиваемых уникальных элементов строит набор троек упорядоченных подмножеств, таких, что в левом один элемент, правое пустое, и в остатке есть только элементы, превышающие элемент левого подмножества

Потом пишем функцию, которая берёт на вход список троек и всеми допустимыми способами расширяет левое (первое) подмножество, элементами третьего
И аналогичную функцию для расширения правого (второго) подмножества.
Функция для правого чуть сложнее, так как из (1) следует, что левое пустым быть не может, а правое может
(2) нам обеспечит изначальное построение соответствующих остатков (третьих множеств)
(5), а так же сокращение перебора в самых массовых подмножествах с относительно коротким остатком, нам обеспечит фильтрация остатка для каждой исходной тройки

def _build_start_1_0_trios( items ) :
    """
    Строим самое первое подмножество подмножеств, в котором в левом по одному, а правое пустое
    За одно вычисляем в каждом случае упорядоченный rest, все элементы в котором больше, 
    чем элемент в левом подмножестве
    """
    items = tuple( sorted( set(items) ) ) #делаем уникальный упорядоченный набор элемнтов
    return [(items[i:i+1], tuple(), items[i+1:]) for i in range(len(items))]

def _gen_add_item_to_left( trios ) :   
    """
    перечисляет результаты возможного расширения левых подмножества, за счёт остатков из той же тройки
    """
    for l, r, rest in trios : #для всех троек
        used = set( l ) | set( r ) # строим остаток, в котором нет элемнтов из l и r
        rest = [c for c in rest if c not in used]
        for c in rest :
            if c > l[-1] : #l пустым быть не может. Строим только упорядоченные подмножества
                yield l+(c,), r, rest

def _gen_add_item_to_right( trios ) :
    """
    перечисляет результаты возможного расширения правых подмножества, за счёт остатков из той же тройки
    """
    for l, r, rest in trios : #для всех троек
        if r : # правое подможество, в отличии от левого, может быть пустым!
            used = set( l ) | set( r ) # строим остаток, в котором нет элемнтов из l и r
            rest = [c for c in rest if c not in used]
            for c in rest :
                if c > r[-1] : # Строим только упорядоченные подмножества
                    yield l, r+(c,), rest
        else : # случай пустого правого подмножества -- некоторые отсечения нельзя выполнить.
            used = set( l ) # строим остаток, в котором нет элемнтов из l и r (но оно всё равно пустое)
            rest = [c for c in rest if c not in used]
            for c in rest :
                yield l, (c,), rest


  "проверим, что получилось"
print( _build_start_1_0_trios( "мама мыла раму милым мылом".split(" ") ) )

print( list( _gen_add_item_to_left([
                                    ( (1,), tuple(), [2,4]),
                                    ( (1, 3), (2,), [2,4,5]),
                                    ( (1, 3), (2, 4), [2,4,5,7]),
                                   ]) ) )

print( list( _gen_add_item_to_right([
                                    ( (1,), tuple(), [2,4]),
                                    ( (1, 3), (2,), [2,4,5]),
                                    ( (1, 3), (2, 4), [2,4,5,7]),
                                   ]) ) )
Печатает:
[(('мама',), (), ('милым', 'мыла', 'мылом', 'раму')), (('милым',), (), ('мыла', 'мылом', 'раму')), (('мыла',), (), ('мылом', 'раму')), (('мылом',), (), ('раму',)), (('раму',), (), ())]
[((1, 2), (), [2, 4]), ((1, 4), (), [2, 4]), ((1, 3, 4), (2,), [4, 5]), ((1, 3, 5), (2,), [4, 5]), ((1, 3, 5), (2, 4), [5, 7]), ((1, 3, 7), (2, 4), [5, 7])]
[((1,), (2,), [2, 4]), ((1,), (4,), [2, 4]), ((1, 3), (2, 4), [4, 5]), ((1, 3), (2, 5), [4, 5]), ((1, 3), (2, 4, 5), [5, 7]), ((1, 3), (2, 4, 7), [5, 7])]


Ну и теперь можем писать сам генератор подмножеств.
Предлагается генерировать подмножества группами, в каждой из которых их размеры одинаковые.
При этом мы так написали _get_subsets_sizes, что обычно можем генерировать новую группу на основе уже сгенерированных, пополняя левое или правое подмножество.
(мы всегда можем это сделать, так как все наборы с меньшей суммой размеров подмножеств мы генерируем до того, как наборы с большей)
К сожалению, из этого правила есть исключение: это случай, когда max_diff == 0, так как в этом случае мы не можем увеличить сумму на 1. И нам придётся в этом случае "преодолевать пропасть в два прыжка"

def gen_sorted_pairs( items, max_diff, max_size ) :
    """
    Генерирует множество пар упорядоченных подмножеств items
    """
    if max_size < 1 : # нечего генерировать
        return
    trios_1_0 = _build_start_1_0_trios(items)
    if max_diff < 1 : # особый случай, когда надо "преодолевать пропасть в два прыжка"
        cur_trios = list( _gen_add_item_to_right(trios_1_0) ) #построили тройки для множеств 1х1
        for t in cur_trios :
            yield (set(t[0]), set(t[1]))
        for i in range(2, max_size+1) :
            # Прыжок №1. Сортируем, что бы удобнее было ориентироваться
            tmp = _gen_add_item_to_left( sorted( cur_trios ) ) # в генерируемых множествах
            # Прыжок №2. Выдаём множества по одному, что бы у перебора была возможность отсечься
            cur_trios = [] # Но, если, нам потребуется и более поздняя группа, сохраняем выданное только что множество
            for t in _gen_add_item_to_right( tmp ):
                cur_trios.append( t )
                yield (set(t[0]), set(t[1]))
    else : # max_diff >= 1 -- можем позволить себе строить подмножества увеличивая их по одному!
        cache = { (1,0):trios_1_0 } # в этом словаре будем хранить наборы множеств, которые планируем расширять
        for size in _get_subsets_sizes(max_size, max_diff, len(items)) :
            left_size, right_size = size
            tmp = []
            if size in cache :
                for t in cache[size] :
                    yield (set(t[0]), set(t[1]))
            elif (left_size, right_size-1) in cache :
                for t in _gen_add_item_to_right( cache[(left_size, right_size-1)] ) :
                    yield (set(t[0]), set(t[1]))
                    tmp.append(t)
                tmp.sort()
                cache[size] = tmp
            elif (left_size-1, right_size) in cache :
                for t in _gen_add_item_to_left( cache[(left_size-1, right_size)] ) :
                    yield (set(t[0]), set(t[1]))
                    tmp.append(t)
                tmp.sort()
                cache[size] = tmp
            else :
                assert False


  "проверим, что получилось"
print( len( list(gen_sorted_pairs([1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12], 0, 4)) ) ) # первое взвешивание
print( len( list(gen_sorted_pairs([1, 2, 3, 4, 5, 6, 7, 8], 4, 4)) ) ) # второе взвешивание
list( gen_sorted_pairs("папа мама я спортивная семья".split(" "), 5, 5 ) )
Печатает:
28116
2703
[({'мама'}, set()),
 ({'папа'}, set()),
 ({'семья'}, set()),
 ({'спортивная'}, set()),
 ({'я'}, set()),
 ({'мама'}, {'папа'}),
 ({'мама'}, {'семья'}),
 ({'мама'}, {'спортивная'}),
 ({'мама'}, {'я'}),
 ({'папа'}, {'семья'}),
 ({'папа'}, {'спортивная'}),
 ({'папа'}, {'я'}),
 ({'семья'}, {'спортивная'}),
 ({'семья'}, {'я'}),
 ({'спортивная'}, {'я'}),
 ({'мама', 'папа'}, set()),
 ({'мама', 'семья'}, set()),
 ({'мама', 'спортивная'}, set()),
 ({'мама', 'я'}, set()),
 ({'папа', 'семья'}, set()),
 ({'папа', 'спортивная'}, set()),
 ({'папа', 'я'}, set()),
 ({'семья', 'спортивная'}, set()),
 ({'семья', 'я'}, set()),
 ({'спортивная', 'я'}, set()),
 ({'мама'}, {'папа', 'семья'}),
 ({'мама'}, {'папа', 'спортивная'}),
 ({'мама'}, {'папа', 'я'}),
 ({'мама'}, {'семья', 'спортивная'}),
 ({'мама'}, {'семья', 'я'}),
 ({'мама'}, {'спортивная', 'я'}),
 ({'папа'}, {'семья', 'спортивная'}),
 ({'папа'}, {'семья', 'я'}),
 ({'папа'}, {'спортивная', 'я'}),
 ({'семья'}, {'спортивная', 'я'}),
 ({'мама', 'папа'}, {'семья'}),
 ({'мама', 'папа'}, {'спортивная'}),
 ({'мама', 'папа'}, {'я'}),
 ({'мама', 'семья'}, {'папа'}),
 ({'мама', 'семья'}, {'спортивная'}),
 ({'мама', 'семья'}, {'я'}),
 ({'мама', 'спортивная'}, {'папа'}),
 ({'мама', 'спортивная'}, {'семья'}),
 ({'мама', 'спортивная'}, {'я'}),
 ({'мама', 'я'}, {'папа'}),
 ({'мама', 'я'}, {'семья'}),
 ({'мама', 'я'}, {'спортивная'}),
 ({'папа', 'семья'}, {'спортивная'}),
 ({'папа', 'семья'}, {'я'}),
 ({'папа', 'спортивная'}, {'семья'}),
 ({'папа', 'спортивная'}, {'я'}),
 ({'папа', 'я'}, {'семья'}),
 ({'папа', 'я'}, {'спортивная'}),
 ({'семья', 'спортивная'}, {'я'}),
 ({'семья', 'я'}, {'спортивная'}),
 ({'мама', 'папа', 'семья'}, set()),
 ({'мама', 'папа', 'спортивная'}, set()),
 ({'мама', 'папа', 'я'}, set()),
 ({'мама', 'семья', 'спортивная'}, set()),
 ({'мама', 'семья', 'я'}, set()),
 ({'мама', 'спортивная', 'я'}, set()),
 ({'папа', 'семья', 'спортивная'}, set()),
 ({'папа', 'семья', 'я'}, set()),
 ({'папа', 'спортивная', 'я'}, set()),
 ({'семья', 'спортивная', 'я'}, set()),
 ({'мама', 'папа'}, {'семья', 'спортивная'}),
 ({'мама', 'папа'}, {'семья', 'я'}),
 ({'мама', 'папа'}, {'спортивная', 'я'}),
 ({'мама', 'семья'}, {'папа', 'спортивная'}),
 ({'мама', 'семья'}, {'папа', 'я'}),
 ({'мама', 'семья'}, {'спортивная', 'я'}),
 ({'мама', 'спортивная'}, {'папа', 'семья'}),
 ({'мама', 'спортивная'}, {'папа', 'я'}),
 ({'мама', 'спортивная'}, {'семья', 'я'}),
 ({'мама', 'я'}, {'папа', 'семья'}),
 ({'мама', 'я'}, {'папа', 'спортивная'}),
 ({'мама', 'я'}, {'семья', 'спортивная'}),
 ({'папа', 'семья'}, {'спортивная', 'я'}),
 ({'папа', 'спортивная'}, {'семья', 'я'}),
 ({'папа', 'я'}, {'семья', 'спортивная'}),
 ({'мама'}, {'папа', 'семья', 'спортивная'}),
 ({'мама'}, {'папа', 'семья', 'я'}),
 ({'мама'}, {'папа', 'спортивная', 'я'}),
 ({'мама'}, {'семья', 'спортивная', 'я'}),
 ({'папа'}, {'семья', 'спортивная', 'я'}),
 ({'мама', 'папа', 'семья'}, {'спортивная'}),
 ({'мама', 'папа', 'семья'}, {'я'}),
 ({'мама', 'папа', 'спортивная'}, {'семья'}),
 ({'мама', 'папа', 'спортивная'}, {'я'}),
 ({'мама', 'папа', 'я'}, {'семья'}),
 ({'мама', 'папа', 'я'}, {'спортивная'}),
 ({'мама', 'семья', 'спортивная'}, {'папа'}),
 ({'мама', 'семья', 'спортивная'}, {'я'}),
 ({'мама', 'семья', 'я'}, {'папа'}),
 ({'мама', 'семья', 'я'}, {'спортивная'}),
 ({'мама', 'спортивная', 'я'}, {'папа'}),
 ({'мама', 'спортивная', 'я'}, {'семья'}),
 ({'папа', 'семья', 'спортивная'}, {'я'}),
 ({'папа', 'семья', 'я'}, {'спортивная'}),
 ({'папа', 'спортивная', 'я'}, {'семья'}),
 ({'мама', 'папа', 'семья', 'спортивная'}, set()),
 ({'мама', 'папа', 'семья', 'я'}, set()),
 ({'мама', 'папа', 'спортивная', 'я'}, set()),
 ({'мама', 'семья', 'спортивная', 'я'}, set()),
 ({'папа', 'семья', 'спортивная', 'я'}, set()),
 ({'мама', 'папа'}, {'семья', 'спортивная', 'я'}),
 ({'мама', 'семья'}, {'папа', 'спортивная', 'я'}),
 ({'мама', 'спортивная'}, {'папа', 'семья', 'я'}),
 ({'мама', 'я'}, {'папа', 'семья', 'спортивная'}),
 ({'мама', 'папа', 'семья'}, {'спортивная', 'я'}),
 ({'мама', 'папа', 'спортивная'}, {'семья', 'я'}),
 ({'мама', 'папа', 'я'}, {'семья', 'спортивная'}),
 ({'мама', 'семья', 'спортивная'}, {'папа', 'я'}),
 ({'мама', 'семья', 'я'}, {'папа', 'спортивная'}),
 ({'мама', 'спортивная', 'я'}, {'папа', 'семья'}),
 ({'мама'}, {'папа', 'семья', 'спортивная', 'я'}),
 ({'мама', 'папа', 'семья', 'спортивная'}, {'я'}),
 ({'мама', 'папа', 'семья', 'я'}, {'спортивная'}),
 ({'мама', 'папа', 'спортивная', 'я'}, {'семья'}),
 ({'мама', 'семья', 'спортивная', 'я'}, {'папа'}),
 ({'мама', 'папа', 'семья', 'спортивная', 'я'}, set())]


Итого, нам осталось написать только сам перебор взвешиваний.
Самую муторнуя часть -- генератор варинтов расположения монет на чашках весов, мы уже написали!


Нам надо перебирать разные стратегии взвешивания, и искать такую, в результате которой у нас в каждом листе дерева будет один исход (такая-то монета фальшивая и мы знаем тяжелее она или легче)

При этом понятно, что на каждом этапе у нас есть какой-то набор монет, про который мы уже знаем, что они не фальшивые, и какой-то набор, про которые ещё не ясно.
Соответственно, ясно, что любое осмысленное взвешивание -- это взвешивание какого-то количества монет, про которые мы пока не знаем, фальшивы ли они против какого-то количества монет из того же множества. При этом число монет на чашах, перед взвешиванием, надо уровнять монетами, которые уже точно нефальшивые.

Итого, любое взвешивание -- это два набора монет (левая и правая чашка), про которые мы пока не знаем, фальшивые ли они. При этом число монет в наборах, может отличаться не больше, чем на количество уже установленных нефальшивых.

Как раз генератор таких множеств мы и написали выше

Теперь надо формализовать саму задачу про взвешивания.

Для удобства занумеруем монеты числами от 1 до числа монет, а возможные результаты поиска фальшивой монеты (какая монета фальшивая и легче она ли тяжелее) за отрицательные номера монет (значит эта фальшивая монета легче) и положительные (значит эта монета тяжелее)

Зачем это надо? Что бы не перебирать, по возможности, эквивалентные стратегии. Например не перебирать разные способы разложить уже установленные нефальшивые монеты.

Итак.
Опишем нашу задачу на языке python 3.
COINS_COUNT = 12 # число монет
SCALE_RESULTS = "<=>" # возможные результаты взвешивания

ALL_COINS = set(range(1,COINS_COUNT+1)) # просто множество всех имеющихся у нас монет   
ALL_STATES = ALL_COINS | {-s for s in ALL_COINS} # а это множество возможных исходов. 

MAX_SPLIT_SIZE = COINS_COUNT // 3 + 1 # Это эвристика, на самом деле её, наверное можно доказать, но можно попробовать запустить с COINS_COUNT.


Обсудим эвристику MAX_SPLIT_SIZE = COINS_COUNT // 3 + 1
На мой взгляд, её можно доказать (если решение существует с полным перебором, то существует и с таким ограничением), но строго доказывать мне лень.
Я пробовал запускать нерешаемые версии задачи (что бы перебирать всё до конца) с этой эвристикой и без неё. Без неё примерно в два раза дольше, так что если очень надо, можно просто отказаться.

Ещё есть эвристика, что если взвешивание не последнее (есть неразличимые состояния), а какой-то результат взвешивания получить нельзя, то эту ветку можно отсечь.
Я пробовал запускать нерешаемую задачу с ней и без неё -- эффект не более 10%. Так что её, для простоты, можно просто не использовать.
В окончательном варианте функции я её закомментировал.

Ну и осталась всего одна вспомогательная задача:
"Взвесить" какой-то набор возможных исходов (то есть применить его к какому-то множеству состояний
def _scale_all_states( left, right, states ) :
    """
    разбить множество состояний на случаи < = >
    """
    res = { "count":None, '<':[], '=':[], '>':[] }
    for s in states :
        if -s in left or s in right :
            res['<'].append( s )
        elif s in left or -s in right :
            res['>'].append( s )
        else :
            res['='].append( s )
    return res


  "проверим, что получилось"
_scale_all_states( {1, 2, 3, 4}, {5, 6, 7, 8}, ALL_STATES )
Печатает:
{'count': None,
 'vs': ({1, 2, 3, 4}, {5, 6, 7, 8}),
 '<': [5, 6, 7, 8, -1, -4, -3, -2],
 '=': [9, 10, 11, 12, 13, -13, -12, -11, -9, -10],
 '>': [1, 2, 3, 4, -8, -7, -6, -5]}


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

def get_scale_strategy( states, max_count, coins_count=None, max_split_size=MAX_SPLIT_SIZE ) :
    """
    Возвращает стратегию взвешинвания на двухчашесных весах, или None, если стратегии нет
    позволяющую найти отличающуюся по весу единственную фальшивую монету в наборе
    states -- множество возвожных исходов
    max_count - максимальное число взвешиваний
    coins_count -- общее число монет. Еслидостоверно нефальшивых сначала нет, то определяется по states
    """
    if len(states) <= 1 : # нечего решать, возвращаем некий формальный результат
        return {"count":0, "vs":(set(),set()), "<":[], "=":list(states), ">":[]} 
    
    if len(states) > 3**max_count :
        return None #отсекаем, так как это множество состояний за оставшееся число взвешиваний не разделяется
    
    unknown = {abs(c) for c in states} # множество монет, про которые пока не ясно, фальшивые ли они
    coins_count = coins_count or len( unknown )
    for l, r in gen_sorted_pairs(unknown, coins_count - len(unknown), max_split_size) :
        scale_res = _scale_all_states( l, r, states )
        #if max_count == 3 and len(l) == 4 and len(r) == 4:
        #    print( l, r, scale_res )
        max_state_len = max( len(scale_res[k]) for k in SCALE_RESULTS )
        if max_state_len > 3**(max_count-1) :
            continue #отсекаем, так как это множество состояний за оставшееся число взвешиваний не разделяется
        if max_state_len <= 1 : # Мы нашли решение за одно взвешивание!!!
            scale_res["count"] = 1
            return scale_res
        #if max( len(scale_res[k]) for k in SCALE_RESULTS ) == 0:
        #    continue #Это только эвристика, но правдоподобная!
        if max_count <= 1 :
            continue # больше ничего сделать нельзя
        
        # Итак, с отсечениями покончено, давайте запускать поиск стратегии рекурсивно!
        scale_count = 0
        for k in SCALE_RESULTS :
            substrategy = get_scale_strategy( scale_res[k], max_count-1, coins_count, max_split_size )
            if substrategy is None : # разделить не удалось!
                scale_res = None
                break
            scale_res[k] = substrategy
            scale_count = max(substrategy["count"], scale_count)
        if scale_res : # Нашли решение для всех трёх результатов взвешивания!
            scale_res["count"] = scale_count + 1
            return scale_res 
    return None


  "проверим, что получилось"
get_scale_strategy( ALL_STATES, 3 )
Печатает (174ms):
{'count': 3,
 'vs': ({1, 2, 3, 7}, {4, 5, 6, 8}),
 '<': {'count': 2,
  'vs': ({1, 2}, {3, 4, 7}),
  '<': {'count': 1, 'vs': ({1}, {2}), '<': [-1], '=': [4], '>': [-2]},
  '=': {'count': 1, 'vs': ({5}, {6}), '<': [6], '=': [8], '>': [5]},
  '>': {'count': 1, 'vs': ({3}, set()), '<': [-3], '=': [-7], '>': []}},
 '=': {'count': 2,
  'vs': ({9}, {10, 11}),
  '<': {'count': 1, 'vs': ({10}, {11}), '<': [11], '=': [-9], '>': [10]},
  '=': {'count': 1, 'vs': ({12}, set()), '<': [-12], '=': [], '>': [12]},
  '>': {'count': 1, 'vs': ({10}, {11}), '<': [-10], '=': [9], '>': [-11]}},
 '>': {'count': 2,
  'vs': ({1, 2}, {3, 4, 7}),
  '<': {'count': 1, 'vs': ({3}, set()), '<': [], '=': [7], '>': [3]},
  '=': {'count': 1, 'vs': ({5}, {6}), '<': [-5], '=': [-8], '>': [-6]},
  '>': {'count': 1, 'vs': ({1}, {2}), '<': [2], '=': [-4], '>': [1]}}}

а
COINS_COUNT = 13
SCALE_RESULTS = "<=>" # возможные результаты взвешивания

ALL_COINS = set(range(1,COINS_COUNT+1))    
ALL_STATES = ALL_COINS | {-s for s in ALL_COINS}
MAX_SPLIT_SIZE = COINS_COUNT

get_strategy( ALL_STATES, 3 )

за 2 секунды находит, что решения нет


Теперь можно пробовать решать разные двухчашечные задачи про уникальные монеты.
Например, проверить, а можно ли так же найти фальшивую среди 40 монет за 4 взвешивания?

  "полная версия кода"
COINS_COUNT = 12
SCALE_RESULTS = "<=>" # возможные результаты взвешивания

ALL_COINS = set(range(1,COINS_COUNT+1))    
ALL_STATES = ALL_COINS | {-s for s in ALL_COINS}
MAX_SPLIT_SIZE = COINS_COUNT

def _get_subsets_sizes( max_size, max_diff, max_sum ) :
    """
    Генерируем последовательность размеров пар подмножеств, таких, 
    что бы каждое следующее можно было получить из какого-то предыдущего
    И что бы сначала перебирать группы множеств с меньшей вариативностью. 
    """
    res = set() # будем строить множество, что бы не париться с повторами, хотя мы и строим каждую пару один раз
    for left_size in range(1, max_size+1) : # леове множество всегда не пустое и максимум max_size
        for right_size in range( max(0, left_size-max_diff), min(max_size, left_size+max_diff ) + 1 ) :
            to_add = left_size, right_size
            assert to_add not in res, f"Повторно сгенерировали пару {to_add}" #это для эстетов
            # Мы уже итерируем такие значения right_size, что 0 <= right_size <= max_size
            # И -max_diff <= right_size - max_size <= max_diff
            if sum(to_add) <= max_sum : # Но есть ещё условие на максимальную сумму размеров
                res.add( to_add ) 
    # множество построено, осталось отсортировать.
    return sorted( res, key=lambda x:(sum(x), max(x), x))

def _build_start_1_0_trios( items ) :
    """
    Строим самое первое подмножество подмножеств, в котором в левом по одному, а правое пустое
    За одно вычисляем в каждом случае упорядоченный rest, все элементы в котором больше, 
    чем элемент в левом подмножестве
    """
    items = tuple( sorted( set(items) ) ) #делаем уникальный упорядоченный набор элемнтов
    return [(items[i:i+1], tuple(), items[i+1:]) for i in range(len(items))]

def _gen_add_item_to_left( trios ) :   
    """
    перечисляет результаты возможного расширения левых подмножества, за счёт остатков из той же тройки
    """
    for l, r, rest in trios : #для всех троек
        used = set( l ) | set( r ) # строим остаток, в котором нет элемнтов из l и r
        rest = [c for c in rest if c not in used]
        for c in rest :
            if c > l[-1] : #l пустым быть не может. Строим только упорядоченные подмножества
                yield l+(c,), r, rest

def _gen_add_item_to_right( trios ) :
    """
    перечисляет результаты возможного расширения правых подмножества, за счёт остатков из той же тройки
    """
    for l, r, rest in trios : #для всех троек
        if r : # правое подможество, в отличии от левого, может быть пустым!
            used = set( l ) | set( r ) # строим остаток, в котором нет элемнтов из l и r
            rest = [c for c in rest if c not in used]
            for c in rest :
                if c > r[-1] : # Строим только упорядоченные подмножества
                    yield l, r+(c,), rest
        else : # случай пустого правого подмножества -- некоторые отсечения нельзя выполнить.
            used = set( l ) # строим остаток, в котором нет элемнтов из l и r (но оно всё равно пустое)
            rest = [c for c in rest if c not in used]
            for c in rest :
                yield l, (c,), rest

def gen_sorted_pairs( items, max_diff, max_size ) :
    """
    Генерирует множество пар упорядоченных подмножеств items
    """
    if max_size < 1 : # нечего генерировать
        return
    trios_1_0 = _build_start_1_0_trios(items)
    if max_diff < 1 : # особый случай, когда надо "преодолевать пропасть в два прыжка"
        cur_trios = list( _gen_add_item_to_right(trios_1_0) ) #построили тройки для множеств 1х1
        for t in cur_trios :
            yield (set(t[0]), set(t[1]))
        for i in range(2, max_size+1) :
            # Прыжок №1. Сортируем, что бы удобнее было ориентироваться
            tmp = _gen_add_item_to_left( sorted( cur_trios ) ) # в генерируемых множествах
            # Прыжок №2. Выдаём множества по одному, что бы у перебора была возможность отсечься
            cur_trios = [] # Но, если, нам потребуется и более поздняя группа, сохраняем выданное только что множество
            for t in _gen_add_item_to_right( tmp ):
                cur_trios.append( t )
                yield (set(t[0]), set(t[1]))
    else : # max_diff >= 1 -- можем позволить себе строить подмножества увеличивая их по одному!
        cache = { (1,0):trios_1_0 } # в этом словаре будем хранить наборы множеств, которые планируем расширять
        for size in _get_subsets_sizes(max_size, max_diff, len(items)) :
            left_size, right_size = size
            tmp = []
            if size in cache :
                for t in cache[size] :
                    yield (set(t[0]), set(t[1]))
            elif (left_size, right_size-1) in cache :
                for t in _gen_add_item_to_right( cache[(left_size, right_size-1)] ) :
                    yield (set(t[0]), set(t[1]))
                    tmp.append(t)
                tmp.sort()
                cache[size] = tmp
            elif (left_size-1, right_size) in cache :
                for t in _gen_add_item_to_left( cache[(left_size-1, right_size)] ) :
                    yield (set(t[0]), set(t[1]))
                    tmp.append(t)
                tmp.sort()
                cache[size] = tmp
            else :
                assert False

def _scale_all_states( left, right, states ) :
    """
    разбить множество состояний на случаи < = >
    """
    res = { "count":None, "vs": (left, right), '<':[], '=':[], '>':[] }
    for s in states :
        if -s in left or s in right :
            res['<'].append( s )
        elif s in left or -s in right :
            res['>'].append( s )
        else :
            res['='].append( s )
    return res
    
def get_scale_strategy( states, max_count, coins_count=None, max_split_size=MAX_SPLIT_SIZE ) :
    """
    Возвращает стратегию взвешинвания на двухчашесных весах, или None, если стратегии нет
    позволяющую найти отличающуюся по весу единственную фальшивую монету в наборе
    states -- множество возвожных исходов
    max_count - максимальное число взвешиваний
    coins_count -- общее число монет. Еслидостоверно нефальшивых сначала нет, то определяется по states
    """
    if len(states) <= 1 : # нечего решать, возвращаем некий формальный результат
        return {"count":0, "vs":(set(),set()), "<":[], "=":list(states), ">":[]} 
    
    if len(states) > 3**max_count :
        return None #отсекаем, так как это множество состояний за оставшееся число взвешиваний не разделяется
    
    unknown = {abs(c) for c in states} # множество монет, про которые пока не ясно, фальшивые ли они
    coins_count = coins_count or len( unknown )
    for l, r in gen_sorted_pairs(unknown, coins_count - len(unknown), max_split_size) :
        scale_res = _scale_all_states( l, r, states )
        #if max_count == 3 and len(l) == 4 and len(r) == 4:
        #    print( l, r, scale_res )
        max_state_len = max( len(scale_res[k]) for k in SCALE_RESULTS )
        if max_state_len > 3**(max_count-1) :
            continue #отсекаем, так как это множество состояний за оставшееся число взвешиваний не разделяется
        if max_state_len <= 1 : # Мы нашли решение за одно взвешивание!!!
            scale_res["count"] = 1
            return scale_res
        #if max( len(scale_res[k]) for k in SCALE_RESULTS ) == 0:
        #    continue #Это только эвристика, но правдоподобная!
        if max_count <= 1 :
            continue # больше ничего сделать нельзя
        
        # Итак, с отсечениями покончено, давайте запускать поиск стратегии рекурсивно!
        scale_count = 0
        for k in SCALE_RESULTS :
            substrategy = get_scale_strategy( scale_res[k], max_count-1, coins_count, max_split_size )
            if substrategy is None : # разделить не удалось!
                scale_res = None
                break
            scale_res[k] = substrategy
            scale_count = max(substrategy["count"], scale_count)
        if scale_res : # Нашли решение для всех трёх результатов взвешивания!
            scale_res["count"] = scale_count + 1
            return scale_res 
    return None

get_scale_strategy( ALL_STATES, 3 )
Все эмоциональные формулировки не соотвествуют действительному положению вещей и приведены мной исключительно "ради красного словца". За корректными формулировками и неискажённым изложением идей, следует обращаться к их автором или воспользоваться поиском
Отредактировано 26.02.2020 18:36 Erop . Предыдущая версия . Еще …
Отредактировано 26.02.2020 18:30 Erop . Предыдущая версия .
Отредактировано 26.02.2020 18:22 Erop . Предыдущая версия .
Отредактировано 26.02.2020 18:20 Erop . Предыдущая версия .
Отредактировано 26.02.2020 18:20 Erop . Предыдущая версия .
Re: Задачке 45+ лет.
От: deimos  
Дата: 04.02.20 13:20
Оценка: +1 :)
Здравствуйте, NovaMind, Вы писали:


NM>Есть 12 монет.

NM>Одна отличается по весу.
NM>За 3(три) взвешиваня найти эту монету и определить тяжелее она или легче.

NM>Image: Libra2.jpg



Быстрее взвестить еще несколько раз, а не оптимизировать число взвешиваний.
При нынешней стоимости взвешиваний это не имеет смысла.
Отредактировано 04.02.2020 13:21 deimos . Предыдущая версия .
Re[2]: Задачке 45+ лет.
От: Erop Россия  
Дата: 21.02.20 18:46
Оценка: +1 :)
Здравствуйте, rg45, Вы писали:

R>По-моему ничего особо сложного.


R>1. Кладем по 4 монеты на каждую чашу


По моему тоже, но ты первый, кто тут смог сформулировать решение. При этом даже люди, которые гуглили, нагуглили не то.
При этом, опять же, ты первый, кто изложил решение не только правильное, но и понятное +100500!!!
Все эмоциональные формулировки не соотвествуют действительному положению вещей и приведены мной исключительно "ради красного словца". За корректными формулировками и неискажённым изложением идей, следует обращаться к их автором или воспользоваться поиском
Re[4]: Вот вам другая задачка
От: xma  
Дата: 11.01.20 11:06
Оценка: 1 (1)
Здравствуйте, Bjorn Skalpe, Вы писали:

xma>>если повезёт — за один день "мгновенно" (точнее, в течение первого же дня)


BS>А если не повезет? Как гарантированно узнать в какой именно бутылке яд?


для меня очевиден только топорный метод

  топорный метод
пр пр
xma>>(100 бутылок x 9 крыс) + (99 бутылок x 1 крыса) + 1 бутылка,

xma>>если крысы через сутки не сдохнут — значит яд в последней бутылке


ну дальше фигачим остатки вина разбиваем на оставшихся в живых крыс — минус одна бутылка

(11 бутылок x9 крыс) + 1 бутылка

(7 бутылок x7 крыс) + (3 бутылки x1 крыс) + 1 бутылки

(2 бутылки x2 крыс) + 1 бутылки

ну т.е. по топорному программерскому методу — 4 дня,


возможно, есть вариант и по аналогии с задачей выше (ну раз ты задал задачу — наверное есть) — за три дня но мне лень разбираться в этом гиммморое

  Скрытый текст
Универсальная методика к решению задач на примере головоломки «12 монет, 3 взвешивания»
https://habr.com/ru/post/447354/
Отредактировано 11.01.2020 11:07 xma . Предыдущая версия . Еще …
Отредактировано 11.01.2020 11:06 xma . Предыдущая версия .
Re[3]: Задачке 45+ лет.
От: NovaMind  
Дата: 11.01.20 07:43
Оценка: +1
Здравствуйте, Muxa, Вы писали:

NM>>Мой папа(Царствие ему небесное) рассказывал, что задачка остановила работу военного НИИ по РСМД на неделю...

M>неделю всем НИИ решали?
M>придумал решение секунд за 20.

Я тоже хвастаться люблю!!!
Re[3]: Вот вам другая задачка
От: xma  
Дата: 11.01.20 17:12
Оценка: +1
Здравствуйте, Anonim, Вы писали:

A>Нумеруем бутылки в двоичной систем получаем 10 битовые числа, а у нас как раз 10 крыс.


да, 2^10 и 10 крыс — навевали мысли о применении "битовых операций", но даже над готовым решением (твоим) — пришлось задумываться ..
Re[2]: Задачке 45+ лет.
От: Пофигист Россия  
Дата: 11.02.20 12:08
Оценка: +1
Здравствуйте, __kot2, Вы писали:

NM>>За 3(три) взвешиваня найти эту монету и определить тяжелее она или легче.

__>меня в таких задачах смущала одна вещь — монеты не могут быть одного веса в принципе.
А практическая бессмысленность ограничения количества взвешиваний не смущала?
Задача же не для практического применения, а для экзамена в гугл мучания детей.
Re: Задачке 45+ лет.
От: rg45 СССР  
Дата: 14.02.20 23:54
Оценка: +1
Здравствуйте, NovaMind, Вы писали:

NM>Есть 12 монет.

NM>Одна отличается по весу.
NM>За 3(три) взвешиваня найти эту монету и определить тяжелее она или легче.

По-моему ничего особо сложного.

1. Кладем по 4 монеты на каждую чашу

2. Если чаши весов оказываются в равновесии, то фальшивой монеты нет среди монет, находяшихся на весах и мы будем использовать эти монеты как эталонные — для находжения фальшивой монеты среди оставшихся четырех монет. Выбираем из этих четырех оставшихся монет любые три и сравниваем их с тремя эталонными. Если эта группа из трех монет оказывается легче или тяжелее эталонных, последним взвешиванием находим среди них фальшивую. Если на этом шаге получаем равновесие, то фальшивой является одна оставшаяся монета и у нас остается одно взвешивание, чтобы определить легче она, или тяжелее.

3. Если при первом взвешивании получаемы разные веса, то с более тяхелой чаши откладываем в сторонку три любые монеты (группа А). Три монеты перекладываем с легкой чаши на тяжелую (группа Б), а на их местко кладем три монеты из группы эталонных. Выполняем второе взвешивание. Если получаем равновесие, значит, фальшивая монета находится в группе монет, отложенных с более тяжелой чаши (группа А) и она тяжелее остальных монет. Находим эту монету последним взвешиванием. Если показания весов изменились на противоположные, значит, фальшивая находится в группе монет, переложенных с более легкой чаши на более тяжелую (группе Б), и она легче остальных монет. Также находим эту монету последним взвешиванием. Если же показания весов не изменились, значит фальшивая монета находится среди пары монет, оставшихся на своих местах после первого взвешивания (по одной монете на каждой чаше). Мы уже знаем, какая из этих двух монет легче, а какая тяжелее и, сравнивая любую из них с эталонной, последним взвешиванием определяем фальшивую.
--
Не можешь достичь желаемого — пожелай достигнутого.
Re[3]: Задачке 45+ лет.
От: rg45 СССР  
Дата: 21.02.20 18:56
Оценка: +1
Здравствуйте, Erop, Вы писали:

E>По моему тоже, но ты первый, кто тут смог сформулировать решение. При этом даже люди, которые гуглили, нагуглили не то.


ИМХО, гугл развращает. Привычка гуглить вытесняет привычку думать. Соображалка не получает достаточной тренировки и постепенно атрофируется.
--
Не можешь достичь желаемого — пожелай достигнутого.
Re[4]: Задачке 45+ лет.
От: Erop Россия  
Дата: 25.02.20 08:34
Оценка: +1
Здравствуйте, NovaMind, Вы писали:

NM>Меня опять терзают смутные сомнения! (с) Иван IV.

NM>Уже Семь недель висит задачка.

NM>Вы... как-то долго...

Я как увидел -- сразу написал. Но я эту задачку раньше знал уже, так что я вообще мгновенно в данном случае.
Правда я всё равно не понимаю, что там можно было тупить?
Там же дерево решений мизерное.
И всегда можно просто попробовать его перебрать с очевидными отсечениями, так, что бы либо доказать, что задачу решить нельзя, либо построить решение.

Очевидно, что из 27 теоретически возможных результатов трёх взвешиваний, надо разделить 24 ситуации. То есть "подклеить" к другой ситуации, или просто заранее знать, мы можем не более трёх комбинаций результатов взвешиваний.

Очевидно, что первых ход -- это взвешивание 4 х 4, так как для 3 х 3 и 5 х 5 потом не получится за 2 взвешивания (9 разных отчётов) выбрать из 10 или 12 ситуаций.

Если 4х4, то либо получаем в ре-те равенство, и надо выбрать из 8 оставшихся вариантов (какая из 4-х монет и тяжелее или легче) Если неравенство, то тоже из 8 (какая из участвовавших во взвешивании фальшивая, так как кто легче или тяжелее уже знаем). Ок.

Например, рассмотрим случай равенства.
Ясно, что нужно так взвешивать, что бы все три исхода были информативны. Поэтому, 2 х 2 из только оставшихся взвешивать неверно, так как не можем получить равенство, а 1 х 1 не верно, так как в случае равенства не понятно, как решить задачу про две монеты и одно взвешивание. Там вроде бы всего два хода остаётся возможных -- сравнить две оставшиеся или сравнить одну из оставшихся с нефальшивой. Ну и все 4 оставшиеся если сравнить с 4 настоящими, тоже мы узнаем тяжелее настоящая или легче, но, потом из 4 за одно взвешивание с тремя исходами выбрать не получится. И ещё можно подозрительные взвешивать в духе 3х1 дополняя настоящими. Но тут тоже не получится узнать какая монета фальшивая и тяжелее ли она.
Значит надо три подозрительные сравнить с тремя настоящими. Если получим равенство, то фальшивая последняя невзвешенная, и за последний ход узнаём тяжелее она или легче.
Если три окажутся тяжелее (или легче) мы узнаем тяжелее ли фальшивая и за последнее взвешивание 1х1 выберем из этих трёх нужную.
Если же первое взвешивание показало неравенство, то у нас 8 подозрительных монет, про каждую из которых мы знаем тяжелее ли она, если она фальшивая.
Значит максимум 3 подозрительные монеты можно отложить на третье взвешивание, а из оставшихся 5 выбрать за два.

Думаем о том, как связаны позиции монет при первом взвешивании и во втором.
Ясно, что монета может остаться там же, где была, может быть отложена и может оказаться на другой чашке весов.
Ясно, что каждая из групп не может превышать 3, так как, если результат второго взвешивания покажет на эту группу, то потом за третье мы из более 3 вариантов не выберем.
Ну и получаем, что или мы три оставляем на своих местах, две перекладываем и три откладываем. Или две оставляем на местах, три перекладываем и три откладываем, или три оставляем на местах, три перекладываем, а две откладываем. Добиваем до ровного числа монет 4 оставшимися, ну и дальше всё тривиально.

Но, даже если не догадаться до идеи о связи первого и второго взвешивания, и ограничить себя только вариантами, когда монета или не участвует во взвешивании, или остаётся на месте. Ок. Предположим мы так "заблудились", хотя мне не понятно, как так можно, если стремиться перебрать ВСЕ варианты (напоминаю, что мы пробуем найти решение или доказать, что его нет).
Но, положим, мы так ошиблись. То сразу возникает вопрос, а как так может получиться, что весы во втором взвешивании покажут другой результат, чем в первом?
Ясно, что позволить себе такую стратегию, при которой такой исход невозможен, мы себе не можем, так как за всего два возможных исхода мы лучше чем до 4 число подозрительных не уменьшим, и всё-таки придётся "изобрести" перекладывание монет между чашками

Вроде бы это полное рассуждение, и оно даёт ВСЕ возможные решения. О чём тут можно думать 2 недели и толпой мне решительно не ясно

NM>P.S.

NM>Это я за папу вступаюсь.

Не надо вступаться, надо попробовать решить таки НОРМАЛЬНО какую-нибудь похожую задачку. Например, для аналогичной задачи для 13 монет (26) вариантов, трёх взвешиваний (27 вариантов результатов взвешивания) можно определить фальшивую и знак её отличия от остальных?
Все эмоциональные формулировки не соотвествуют действительному положению вещей и приведены мной исключительно "ради красного словца". За корректными формулировками и неискажённым изложением идей, следует обращаться к их автором или воспользоваться поиском
Отредактировано 25.02.2020 19:45 Erop . Предыдущая версия .
Re[10]: Задачке 45+ лет.
От: Khimik  
Дата: 11.03.20 14:40
Оценка: +1
E>>Это всё неинтересно. Интересно написать решалку задач такого типа для большего числа взвешиваний.
E>>Например, про сколько монет можно определить какая фальшивая и тяжелее она или легче за 10 взвешиваний?
V>Ну если тебе нефиг делать, то можешь приступать.

За одно взвешивание получаем примерно полтора бита информации: либо левые весы тяжелее, либо правые, либо равенство — т.е. один из трёх вариантов.

3^10=59049

Это число надо поделить на два, поскольку есть дополнительный бит информации который надо определить — тяжелее или легче фальшивая монета:

59049/2=29524,5

Получается что ответ 29524 монеты. Правда тут наверняка реальное число меньше, поскольку не всегда можно равномерно разделить варианты. Из этого подхода получается что можно решить исходную задачу не только с 12, но и с 13 монетами, сомневаюсь что это возможно реально.
"Ты должен сделать добро из зла, потому что его больше не из чего сделать". АБ Стругацкие.
Задачке 45+ лет.
От: NovaMind  
Дата: 11.01.20 00:41
Оценка:
Есть 12 монет.
Одна отличается по весу.
За 3(три) взвешиваня найти эту монету и определить тяжелее она или легче.

Отредактировано 11.01.2020 1:14 NovaMind . Предыдущая версия .
Re: Задачке 45+ лет.
От: NovaMind  
Дата: 11.01.20 01:15
Оценка:
Здравствуйте, NovaMind, Вы писали:


NM>Есть 12 монет.

NM>Одна отличается по весу.
NM>За 3(три) взвешиваня найти эту монету и определить тяжелее она или легче.

NM>Image: Libra2.jpg

Мой папа(Царствие ему небесное) рассказывал, что задачка остановила работу военного НИИ по РСМД на неделю...
Re[2]: Задачке 45+ лет.
От: Эйнсток Файр Мухосранск Странный реагент
Дата: 11.01.20 01:59
Оценка:
NM> задачка остановила работу военного НИИ по РСМД на неделю...

У них интернета не было:
https://habr.com/ru/post/447354/
Re[3]: Задачке 45+ лет.
От: NovaMind  
Дата: 11.01.20 02:01
Оценка:
Здравствуйте, Эйнсток Файр, Вы писали:

NM>> задачка остановила работу военного НИИ по РСМД на неделю...


ЭФ>У них интернета не было:

ЭФ>https://habr.com/ru/post/447354/
Не было!!!
Вот облом...
Re[4]: Задачке 45+ лет.
От: takTak  
Дата: 11.01.20 07:36
Оценка:
NM>>> задачка остановила работу военного НИИ по РСМД на неделю...

ЭФ>>У них интернета не было:

ЭФ>>https://habr.com/ru/post/447354/
NM>Не было!!!
NM>Вот облом...

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


если вначале 12 элементов поделить на две группы, взвесить 6 и 6, найдётся та группа из 6, где находится более тяжёлая часть,
потом эти 6 делятся на две группы по 3, опять находим группу, где находится более тяжёлая часть,
наконец, в конце берём два любых элемента и взвешиваем- либо один из них тяжелее, а если нет, то тяжёлым является тот элемент, который не взвешивали

а, я неправильно прочитал, элемент может быть и легче... тогда да,тогда так просто не получится...
Отредактировано 11.01.2020 7:38 takTak . Предыдущая версия .
Re[5]: Задачке 45+ лет.
От: NovaMind  
Дата: 11.01.20 07:41
Оценка:
Здравствуйте, takTak, Вы писали:

NM>>>> задачка остановила работу военного НИИ по РСМД на неделю...


ЭФ>>>У них интернета не было:

ЭФ>>>https://habr.com/ru/post/447354/
NM>>Не было!!!
NM>>Вот облом...

T>не понял, зачем в указанном решении 12 элементов делятся на 3 группы...



T>если вначале 12 элементов поделить на две группы, взвесить 6 и 6, найдётся та группа из 6, где находится более тяжёлая часть,

T>потом эти 6 делятся на две группы по 3, опять находим группу, где находится более тяжёлая часть,
T>наконец, в конце берём два любых элемента и взвешиваем- либо один из них тяжелее, а если нет, то тяжёлым является тот элемент, который не взвешивали

Условие задачи прочитайте. Вдумчиво....

"... и определить тяжелее она или легче."
Re: Вот вам другая задачка
От: Bjorn Skalpe Земля  
Дата: 11.01.20 09:54
Оценка:
Есть 1000 бутылок вина, одна бутылка отравлена. Есть 10 крыс. 1 капля вина гарантированно убивает крысу. Крыс можно поить 1 раз в день. За сколько минимально дней можно определить в какой бутылке яд?

upd. Процесс умирания крысы происходит не мгновенно, а за 1 день.
Отредактировано 11.01.2020 10:50 Bjorn Skalpe . Предыдущая версия . Еще …
Отредактировано 11.01.2020 10:49 Bjorn Skalpe . Предыдущая версия .
Отредактировано 11.01.2020 10:48 Bjorn Skalpe . Предыдущая версия .
Отредактировано 11.01.2020 10:44 Bjorn Skalpe . Предыдущая версия .
Отредактировано 11.01.2020 10:44 Bjorn Skalpe . Предыдущая версия .
Отредактировано 11.01.2020 10:42 Bjorn Skalpe . Предыдущая версия .
Re[2]: Вот вам другая задачка
От: xma  
Дата: 11.01.20 10:09
Оценка:
Здравствуйте, Bjorn Skalpe, Вы писали:

BS>Есть 1000 бутылок вина, одна бутылка отравлена. Есть 10 крыс. 1 капля вина гарантированно убивает крысу. Крыс можно поить 1 раз в день. За сколько минимально дней можно определить в какой бутылке яд?


если повезёт — за один день "мгновенно" (точнее, в течение первого же дня)

(100 бутылок x 9 крыс) + (99 бутылок x 1 крыса) + 1 бутылка,

если крысы через сутки не сдохнут — значит яд в последней бутылке
Отредактировано 11.01.2020 10:15 xma . Предыдущая версия . Еще …
Отредактировано 11.01.2020 10:15 xma . Предыдущая версия .
Отредактировано 11.01.2020 10:14 xma . Предыдущая версия .
Отредактировано 11.01.2020 10:13 xma . Предыдущая версия .
Re[3]: Вот вам другая задачка
От: Bjorn Skalpe Земля  
Дата: 11.01.20 10:48
Оценка:
Здравствуйте, xma, Вы писали:

xma>Здравствуйте, Bjorn Skalpe, Вы писали:


BS>>Есть 1000 бутылок вина, одна бутылка отравлена. Есть 10 крыс. 1 капля вина гарантированно убивает крысу. Крыс можно поить 1 раз в день. За сколько минимально дней можно определить в какой бутылке яд?


xma>если повезёт — за один день "мгновенно" (точнее, в течение первого же дня)


А если не повезет? Как гарантированно узнать в какой именно бутылке яд?

xma>(100 бутылок x 9 крыс) + (99 бутылок x 1 крыса) + 1 бутылка,


xma>если крысы через сутки не сдохнут — значит яд в последней бутылке
Отредактировано 11.01.2020 10:50 Bjorn Skalpe . Предыдущая версия . Еще …
Отредактировано 11.01.2020 10:50 Bjorn Skalpe . Предыдущая версия .
Re[3]: Вот вам другая задачка
От: Bjorn Skalpe Земля  
Дата: 11.01.20 16:15
Оценка:
Здравствуйте, Anonim, Вы писали:

A>Здравствуйте, Bjorn Skalpe, Вы писали:


BS>>Есть 1000 бутылок вина, одна бутылка отравлена. Есть 10 крыс. 1 капля вина гарантированно убивает крысу. Крыс можно поить 1 раз в день. За сколько минимально дней можно определить в какой бутылке яд?


BS>>upd. Процесс умирания крысы происходит не мгновенно, а за 1 день.


A>Нумеруем бутылки в двоичной систем получаем 10 битовые числа, а у нас как раз 10 крыс.

A>Каждой крысе наливаем по капли из всех бутылок где ее бит равен 1.
A>Соответственно на следующий день, узнаем номер бутылки.
A>Если сдохли все значит 512 капель хорошего вина убивает крысу.

Умничка. Только можно выполнить операцию AND по каплям по разрядам с 1, что бы не поить первую крысу 512 каплями... будем считать что свойства яда не исчезают при смешивании.
Отредактировано 11.01.2020 16:28 Bjorn Skalpe . Предыдущая версия . Еще …
Отредактировано 11.01.2020 16:27 Bjorn Skalpe . Предыдущая версия .
Отредактировано 11.01.2020 16:27 Bjorn Skalpe . Предыдущая версия .
Re[4]: Вот вам другая задачка
От: Anonim  
Дата: 11.01.20 20:49
Оценка:
BS>Умничка. Только можно выполнить операцию AND по каплям по разрядам с 1, что бы не поить первую крысу 512 каплями... будем считать что свойства яда не исчезают при смешивании.

Ступил, просто хотелось поиграть в Петросяна.
Re[5]: Задачке 45+ лет.
От: kgd  
Дата: 12.01.20 12:15
Оценка:
Здравствуйте, takTak, Вы писали:

T>если вначале 12 элементов поделить на две группы, взвесить 6 и 6, найдётся та группа из 6, где находится более тяжёлая часть,

T>потом эти 6 делятся на две группы по 3, опять находим группу, где находится более тяжёлая часть,
T>наконец, в конце берём два любых элемента и взвешиваем- либо один из них тяжелее, а если нет, то тяжёлым является тот элемент, который не взвешивали

T>а, я неправильно прочитал, элемент может быть и легче... тогда да,тогда так просто не получится...


Тяжелее он или легче — понятно из первого взвешивания групп.
Re[6]: Задачке 45+ лет.
От: kgd  
Дата: 12.01.20 12:18
Оценка:
Здравствуйте, NovaMind, Вы писали:


T>>если вначале 12 элементов поделить на две группы, взвесить 6 и 6, найдётся та группа из 6, где находится более тяжёлая часть,

T>>потом эти 6 делятся на две группы по 3, опять находим группу, где находится более тяжёлая часть,
T>>наконец, в конце берём два любых элемента и взвешиваем- либо один из них тяжелее, а если нет, то тяжёлым является тот элемент, который не взвешивали

NM>Условие задачи прочитайте. Вдумчиво....


NM>"... и определить тяжелее она или легче."


Если 10-я и 11-я взвешиваемые монеты равны по весу, то из предыдущего взвешивания мы знаем, что (10-я+11-я+12-я) монеты тяжелее или легче других трех монет.
Соответственно 12-я легче или тяжелее.

Задачка не для поколения твиттера с памятью на 1 итерацию
Re[7]: Задачке 45+ лет.
От: NovaMind  
Дата: 15.01.20 13:48
Оценка:
Здравствуйте, kgd, Вы писали:

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



T>>>если вначале 12 элементов поделить на две группы, взвесить 6 и 6, найдётся та группа из 6, где находится более тяжёлая часть,

T>>>потом эти 6 делятся на две группы по 3, опять находим группу, где находится более тяжёлая часть,
T>>>наконец, в конце берём два любых элемента и взвешиваем- либо один из них тяжелее, а если нет, то тяжёлым является тот элемент, который не взвешивали

NM>>Условие задачи прочитайте. Вдумчиво....


NM>>"... и определить тяжелее она или легче."


kgd>Если 10-я и 11-я взвешиваемые монеты равны по весу, то из предыдущего взвешивания мы знаем, что (10-я+11-я+12-я) монеты тяжелее или легче других трех монет.

kgd>Соответственно 12-я легче или тяжелее.

Ну и как?
Легче или тяжелее?

kgd>Задачка не для поколения твиттера с памятью на 1 итерацию


Ну-ну...
Re[6]: Задачке 45+ лет.
От: NovaMind  
Дата: 15.01.20 13:55
Оценка:
Здравствуйте, kgd, Вы писали:

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


T>>если вначале 12 элементов поделить на две группы, взвесить 6 и 6, найдётся та группа из 6, где находится более тяжёлая часть,

T>>потом эти 6 делятся на две группы по 3, опять находим группу, где находится более тяжёлая часть,
T>>наконец, в конце берём два любых элемента и взвешиваем- либо один из них тяжелее, а если нет, то тяжёлым является тот элемент, который не взвешивали

T>>а, я неправильно прочитал, элемент может быть и легче... тогда да,тогда так просто не получится...


kgd>Тяжелее он или легче — понятно из первого взвешивания групп.


Т.е. одна группа легче, а другая тяжелее.
Это и я понял.
А что с неправильной монетой?
Она как?
Легче или тяжелее?

Каков Ваш вывод?
Говорите! Не стесняйтесь!
Re[7]: Задачке 45+ лет.
От: Khimik  
Дата: 17.01.20 13:01
Оценка:
Здравствуйте, NovaMind, Вы писали:


NM>Каков Ваш вывод?

NM>Говорите! Не стесняйтесь!

Если при взвешивании определяется точный вес груза, я предлагаю разрезать монеты на доли. Тогда можно обойтись двумя взвешиваниями: в первом определяется вес неправильной монеты, во втором взвешиваются доли монет — 1/12 от первой монеты, 2/12 от второй и т.д. По точному весу можно получить нужную информацию.
"Ты должен сделать добро из зла, потому что его больше не из чего сделать". АБ Стругацкие.
Re[8]: Задачке 45+ лет.
От: marcopolo Россия  
Дата: 18.01.20 16:14
Оценка:
Здравствуйте, NovaMind, Вы писали:

NM>Ну и как?

NM>Легче или тяжелее?

kgd>>Задачка не для поколения твиттера с памятью на 1 итерацию


NM>Ну-ну...


Re: Задачке 45+ лет.
От: Vain Россия google.ru
Дата: 24.01.20 14:29
Оценка:
Здравствуйте, NovaMind, Вы писали:

NM>Есть 12 монет.

NM>Одна отличается по весу.
NM>За 3(три) взвешиваня найти эту монету и определить тяжелее она или легче.
NM>Image: Libra2.jpg
Задача сводится к последующему взвешиванию (начиная со второго) с отбрасыванием 3х: перестановкой 2х c заменой одной на взвешенную.

Первое взвешивание:
4 x 4, если равно, то монета в остальных 4х: (fixed) решение для них тут: http://rsdn.org/forum/education/7677064
Автор: Vain
Дата: 10.03.20

Разность на весах покажет, что фальшивая монета на весах. Равно покажет — в оставшейся стопке.

Второй взвешивание:

(A)
         <проверяемые>         | <остаток>
  o  o  o  o   :   o  o  o  o  |  o  o  o  o
 x1 x2 x3 x4       y1 y2 y3 y4 |  z1 z2 z3 z4

Тут делаем финт ушами до такого:
(B)
         <проверяемые>         | <остаток>
  o  o  o      :   o  o  o     |  o  o  o
  x1 y1 y2         x2 x3 z1    |  x4 y3 y4

(C)
         <проверяемые>         | <остаток>
  o            :   o           |  o
  y3               x4          |  y4


+ у нас информация с предыдущего шага: больше или меньше, т.к. на равно мы уже проверили и монета бы была найдена среди z1..z4.

Первые два взвешивания:

монета | (A) | (B)
-------+-----+-----
x1 > < | > < | > <
x2 > < | > < | < >
x3 > < | > < | < >
y1 > < | < > | > <
y2 > < | < > | > <

Если (B) даёт равно, то взвешиваем (C):
монета | (A) | (C)
-------+-----+-----
x4 > < | > < | < >
y3 > < | < > | > <
y4 > < | < > |  =

Если (B) даёт разность, то осталось проверить x2, x3, y1, y2, т.к. x1 имеет уникальный паттерн.
(D)
         <проверяемые>         | <остаток>
  o  o         :   o  o        |  o
  x2 y1            x3 z1       |  y2

монета | (A) | (B) | (D)
-------+-----+-----+----
x2 > < | > < | < > | > <
x3 > < | > < | < > | < >
y1 > < | < > | > < | > <

< — меньше/легче
> — больше/тяжелее

Как то так.
[In theory there is no difference between theory and practice. In
practice there is.]
[Даю очевидные ответы на риторические вопросы]
Отредактировано 10.03.2020 17:01 Vain . Предыдущая версия .
Re: Задачке 45+ лет.
От: __kot2  
Дата: 27.01.20 05:12
Оценка:
Здравствуйте, NovaMind, Вы писали:
NM>Есть 12 монет.
NM>Одна отличается по весу.
NM>За 3(три) взвешиваня найти эту монету и определить тяжелее она или легче.
меня в таких задачах смущала одна вещь — монеты не могут быть одного веса в принципе. где-то потертые, где-то грязные, в разное время отчеканенные из чуть разного металла. и мы не знаем насколько отличается по весу фальшивая. то есть вот ты взвесил весами 2 стопки по 4 и вот видишь что весы на миллиметр отклоняются. это за что считается? за равный вес или что одна тяжелее другой?

например, вес обычной монеты может колебаться +-0.1 грамма, а вес фальшифой дает -0.5 грамма, что, конечно, заметно.
но при этом при взвешивании 6 монет, где на левую часть попадет фальшивая и 5 с перевесом 0.1 легко перевесят вторую чашку где будет 5 с недовесом 0.1. и это будет так даже если пару монет туда-сюда перекинуть

вот не люблю я вообще задачи где аффтаром подразумевается точность сравнения там, скоростей, весов или размеров. типа, два дерева могут быть одной высоты или там, два человека одного веса. ага, щаз

если бы такую задачу решал бы действительно человек, изображенный на картинке из поста, он бы искал монету, которая легче, ясен пень. от драг металлов откусывали кусочки и потом накатывали рельеф поверху. уже стало понятно и без взвешиваний. потом он бы скорее всего взял некую стандартную мерную монету, измерил бы каждую в сравнении с ней и записал бы, насколько каждая из монет убыла в весе и именно это было бы ценной информацией, а не непонятные приседания с весами
Отредактировано 27.01.2020 5:35 __kot2 . Предыдущая версия . Еще …
Отредактировано 27.01.2020 5:21 __kot2 . Предыдущая версия .
Отредактировано 27.01.2020 5:20 __kot2 . Предыдущая версия .
Re: Задачке 45+ лет.
От: MasterZiv СССР  
Дата: 03.02.20 14:34
Оценка:
Здравствуйте, NovaMind, Вы писали:


NM>Есть 12 монет.

NM>Одна отличается по весу.
NM>За 3(три) взвешиваня найти эту монету и определить тяжелее она или легче.

Так легко же!
Re[2]: Задачке 45+ лет.
От: Sinclair Россия https://github.com/evilguest/
Дата: 05.02.20 16:59
Оценка:
Здравствуйте, deimos, Вы писали:

D>Быстрее взвестить еще несколько раз, а не оптимизировать число взвешиваний.

D>При нынешней стоимости взвешиваний это не имеет смысла.
Точнее, мы просто ставим 6 весов, и проводим 6 попарных взвешиваний одновременно. Потом переставляем монеты, и узнаём точный результат.
Уйдемте отсюда, Румата! У вас слишком богатые погреба.
Re[2]: Задачке 45+ лет.
От: Erop Россия  
Дата: 21.02.20 18:23
Оценка:
Здравствуйте, NovaMind, Вы писали:

NM>>Image: Libra2.jpg

NM>Мой папа(Царствие ему небесное) рассказывал, что задачка остановила работу военного НИИ по РСМД на неделю...

Что-то они тупили, как-то долго...
Все эмоциональные формулировки не соотвествуют действительному положению вещей и приведены мной исключительно "ради красного словца". За корректными формулировками и неискажённым изложением идей, следует обращаться к их автором или воспользоваться поиском
Re[3]: Задачке 45+ лет.
От: Erop Россия  
Дата: 21.02.20 18:24
Оценка:
Здравствуйте, Эйнсток Файр, Вы писали:

ЭФ>У них интернета не было:

ЭФ>https://habr.com/ru/post/447354/

Это вроде бы не решение. Там не всегда можно сказать тяжелее фальшивая или легче...
Все эмоциональные формулировки не соотвествуют действительному положению вещей и приведены мной исключительно "ради красного словца". За корректными формулировками и неискажённым изложением идей, следует обращаться к их автором или воспользоваться поиском
Re[2]: Задачке 45+ лет.
От: Erop Россия  
Дата: 21.02.20 18:33
Оценка:
Здравствуйте, Vain, Вы писали:

V>Первое взвешивание:

V>4 x 4, если равно, то монета в остальных 4х. Тут просто взвешиваем 1 x 1 второй попыткой и ещё 1 x 1 третьей, где одна монета уже взвешена.
V>Разность на весах покажет, что фальшивая монета на весах. Равно покажет — в оставшейся стопке.

Так?
1. 1+2+3+4 == 5+6+7+8 => фальшивая среди 9, 10, 11 ,12
2. 9 +10 == 1+2 => фальшивая среди 11 и 12
3. 11 == 1 => фальшивая 12, но тяжелее она или легче?
Все эмоциональные формулировки не соотвествуют действительному положению вещей и приведены мной исключительно "ради красного словца". За корректными формулировками и неискажённым изложением идей, следует обращаться к их автором или воспользоваться поиском
Re[2]: Задачке 45+ лет.
От: Erop Россия  
Дата: 21.02.20 18:42
Оценка:
Здравствуйте, __kot2, Вы писали:

__>меня в таких задачах смущала одна вещь — монеты не могут быть одного веса в принципе. где-то потертые, где-то грязные, в разное время отчеканенные из чуть разного металла. и мы не знаем насколько отличается по весу фальшивая.


Это же мат. задача, условность, а не урок банковского дела...

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


Вообще-то, в истории известны примеры, когда фальшивые монеты были тяжелее настоящих. Демидовки, например...
Все эмоциональные формулировки не соотвествуют действительному положению вещей и приведены мной исключительно "ради красного словца". За корректными формулировками и неискажённым изложением идей, следует обращаться к их автором или воспользоваться поиском
Re[3]: Задачке 45+ лет.
От: NovaMind  
Дата: 23.02.20 01:23
Оценка:
Здравствуйте, Erop, Вы писали:

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


NM>>>Image: Libra2.jpg

NM>>Мой папа(Царствие ему небесное) рассказывал, что задачка остановила работу военного НИИ по РСМД на неделю...

E>Что-то они тупили, как-то долго...


Меня опять терзают смутные сомнения! (с) Иван IV.
Уже Семь недель висит задачка.

Вы... как-то долго...

P.S.
Это я за папу вступаюсь.
Re[5]: Задачке 45+ лет.
От: NovaMind  
Дата: 23.02.20 10:31
Оценка:
Здравствуйте, deimos, Вы писали:

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


NM>>Я тоже хвастаться люблю!!!


D>А я никогда не хвастаюсь, потому что гении скромные!


Я тоже никогда не хвастаюсь, но люблю!

И гении имеют свои слабости...
Re[2]: Задачке 45+ лет.
От: Erop Россия  
Дата: 27.02.20 09:29
Оценка:
E>Здравствуйте, NovaMind, Вы писали:

NM>>Есть 12 монет.

NM>>Одна отличается по весу.
NM>>За 3(три) взвешиваня найти эту монету и определить тяжелее она или легче.

NM>>Image: Libra2.jpg



E>
  "полная версия кода"
E>COINS_COUNT = 12
E>SCALE_RESULTS = "<=>" # возможные результаты взвешивания

E>ALL_COINS = set(range(1,COINS_COUNT+1))    
E>ALL_STATES = ALL_COINS | {-s for s in ALL_COINS}
E>MAX_SPLIT_SIZE = COINS_COUNT

E>def _get_subsets_sizes( max_size, max_diff, max_sum ) :
E>    """
E>    Генерируем последовательность размеров пар подмножеств, таких, 
E>    что бы каждое следующее можно было получить из какого-то предыдущего
E>    И что бы сначала перебирать группы множеств с меньшей вариативностью. 
E>    """
E>    res = set() # будем строить множество, что бы не париться с повторами, хотя мы и строим каждую пару один раз
E>    for left_size in range(1, max_size+1) : # леове множество всегда не пустое и максимум max_size
E>        for right_size in range( max(0, left_size-max_diff), min(max_size, left_size+max_diff ) + 1 ) :
E>            to_add = left_size, right_size
E>            assert to_add not in res, f"Повторно сгенерировали пару {to_add}" #это для эстетов
E>            # Мы уже итерируем такие значения right_size, что 0 <= right_size <= max_size
E>            # И -max_diff <= right_size - max_size <= max_diff
E>            if sum(to_add) <= max_sum : # Но есть ещё условие на максимальную сумму размеров
E>                res.add( to_add ) 
E>    # множество построено, осталось отсортировать.
E>    return sorted( res, key=lambda x:(sum(x), max(x), x))

E>def _build_start_1_0_trios( items ) :
E>    """
E>    Строим самое первое подмножество подмножеств, в котором в левом по одному, а правое пустое
E>    За одно вычисляем в каждом случае упорядоченный rest, все элементы в котором больше, 
E>    чем элемент в левом подмножестве
E>    """
E>    items = tuple( sorted( set(items) ) ) #делаем уникальный упорядоченный набор элемнтов
E>    return [(items[i:i+1], tuple(), items[i+1:]) for i in range(len(items))]

E>def _gen_add_item_to_left( trios ) :   
E>    """
E>    перечисляет результаты возможного расширения левых подмножества, за счёт остатков из той же тройки
E>    """
E>    for l, r, rest in trios : #для всех троек
E>        used = set( l ) | set( r ) # строим остаток, в котором нет элемнтов из l и r
E>        rest = [c for c in rest if c not in used]
E>        for c in rest :
E>            if c > l[-1] : #l пустым быть не может. Строим только упорядоченные подмножества
E>                yield l+(c,), r, rest

E>def _gen_add_item_to_right( trios ) :
E>    """
E>    перечисляет результаты возможного расширения правых подмножества, за счёт остатков из той же тройки
E>    """
E>    for l, r, rest in trios : #для всех троек
E>        if r : # правое подможество, в отличии от левого, может быть пустым!
E>            used = set( l ) | set( r ) # строим остаток, в котором нет элемнтов из l и r
E>            rest = [c for c in rest if c not in used]
E>            for c in rest :
E>                if c > r[-1] : # Строим только упорядоченные подмножества
E>                    yield l, r+(c,), rest
E>        else : # случай пустого правого подмножества -- некоторые отсечения нельзя выполнить.
E>            used = set( l ) # строим остаток, в котором нет элемнтов из l и r (но оно всё равно пустое)
E>            rest = [c for c in rest if c not in used]
E>            for c in rest :
E>                yield l, (c,), rest

E>def gen_sorted_pairs( items, max_diff, max_size ) :
E>    """
E>    Генерирует множество пар упорядоченных подмножеств items
E>    """
E>    if max_size < 1 : # нечего генерировать
E>        return
E>    trios_1_0 = _build_start_1_0_trios(items)
E>    if max_diff < 1 : # особый случай, когда надо "преодолевать пропасть в два прыжка"
E>        cur_trios = list( _gen_add_item_to_right(trios_1_0) ) #построили тройки для множеств 1х1
E>        for t in cur_trios :
E>            yield (set(t[0]), set(t[1]))
E>        for i in range(2, max_size+1) :
E>            # Прыжок №1. Сортируем, что бы удобнее было ориентироваться
E>            tmp = _gen_add_item_to_left( sorted( cur_trios ) ) # в генерируемых множествах
E>            # Прыжок №2. Выдаём множества по одному, что бы у перебора была возможность отсечься
E>            cur_trios = [] # Но, если, нам потребуется и более поздняя группа, сохраняем выданное только что множество
E>            for t in _gen_add_item_to_right( tmp ):
E>                cur_trios.append( t )
E>                yield (set(t[0]), set(t[1]))
E>    else : # max_diff >= 1 -- можем позволить себе строить подмножества увеличивая их по одному!
E>        cache = { (1,0):trios_1_0 } # в этом словаре будем хранить наборы множеств, которые планируем расширять
E>        for size in _get_subsets_sizes(max_size, max_diff, len(items)) :
E>            left_size, right_size = size
E>            tmp = []
E>            if size in cache :
E>                for t in cache[size] :
E>                    yield (set(t[0]), set(t[1]))
E>            elif (left_size, right_size-1) in cache :
E>                for t in _gen_add_item_to_right( cache[(left_size, right_size-1)] ) :
E>                    yield (set(t[0]), set(t[1]))
E>                    tmp.append(t)
E>                tmp.sort()
E>                cache[size] = tmp
E>            elif (left_size-1, right_size) in cache :
E>                for t in _gen_add_item_to_left( cache[(left_size-1, right_size)] ) :
E>                    yield (set(t[0]), set(t[1]))
E>                    tmp.append(t)
E>                tmp.sort()
E>                cache[size] = tmp
E>            else :
E>                assert False

E>def _scale_all_states( left, right, states ) :
E>    """
E>    разбить множество состояний на случаи < = >
E>    """
E>    res = { "count":None, "vs": (left, right), '<':[], '=':[], '>':[] }
E>    for s in states :
E>        if -s in left or s in right :
E>            res['<'].append( s )
E>        elif s in left or -s in right :
E>            res['>'].append( s )
E>        else :
E>            res['='].append( s )
E>    return res
    
E>def get_scale_strategy( states, max_count, coins_count=None, max_split_size=MAX_SPLIT_SIZE ) :
E>    """
E>    Возвращает стратегию взвешинвания на двухчашесных весах, или None, если стратегии нет
E>    позволяющую найти отличающуюся по весу единственную фальшивую монету в наборе
E>    states -- множество возвожных исходов
E>    max_count - максимальное число взвешиваний
E>    coins_count -- общее число монет. Еслидостоверно нефальшивых сначала нет, то определяется по states
E>    """
E>    if len(states) <= 1 : # нечего решать, возвращаем некий формальный результат
E>        return {"count":0, "vs":(set(),set()), "<":[], "=":list(states), ">":[]} 
    
E>    if len(states) > 3**max_count :
E>        return None #отсекаем, так как это множество состояний за оставшееся число взвешиваний не разделяется
    
E>    unknown = {abs(c) for c in states} # множество монет, про которые пока не ясно, фальшивые ли они
E>    coins_count = coins_count or len( unknown )
E>    for l, r in gen_sorted_pairs(unknown, coins_count - len(unknown), max_split_size) :
E>        scale_res = _scale_all_states( l, r, states )
E>        #if max_count == 3 and len(l) == 4 and len(r) == 4:
E>        #    print( l, r, scale_res )
E>        max_state_len = max( len(scale_res[k]) for k in SCALE_RESULTS )
E>        if max_state_len > 3**(max_count-1) :
E>            continue #отсекаем, так как это множество состояний за оставшееся число взвешиваний не разделяется
E>        if max_state_len <= 1 : # Мы нашли решение за одно взвешивание!!!
E>            scale_res["count"] = 1
E>            return scale_res
E>        #if max( len(scale_res[k]) for k in SCALE_RESULTS ) == 0:
E>        #    continue #Это только эвристика, но правдоподобная!
E>        if max_count <= 1 :
E>            continue # больше ничего сделать нельзя
        
E>        # Итак, с отсечениями покончено, давайте запускать поиск стратегии рекурсивно!
E>        scale_count = 0
E>        for k in SCALE_RESULTS :
E>            substrategy = get_scale_strategy( scale_res[k], max_count-1, coins_count, max_split_size )
E>            if substrategy is None : # разделить не удалось!
E>                scale_res = None
E>                break
E>            scale_res[k] = substrategy
E>            scale_count = max(substrategy["count"], scale_count)
E>        if scale_res : # Нашли решение для всех трёх результатов взвешивания!
E>            scale_res["count"] = scale_count + 1
E>            return scale_res 
E>    return None

E>get_scale_strategy( ALL_STATES, 3 )
E>


E>Теперь можно пробовать решать разные двухчашечные задачи про уникальные монеты.

E>Например, проверить, а можно ли так же найти фальшивую среди 40 монет за 4 взвешивания?
На самом деле решения с 40 монетами за 4 взвешивания, очевидно, не существует. Ясно, что если после первого взвешивания будет равенство, то оставшиеся монеты будут играть в похожую игру — один ход, но + запас заведомо честных монет. Очевидно, что для 14 монет (28) исходов 3 взвешиваниями (27 исходов) она не решается, а для того, что бы получить меньшее число, надо первым ходом взвешивать 14х14. А это, опять по 28 исходов в случае неравенство.

Но легко проверить, например, что с первым ходом 8х8 это ещё решается, что даёт нам 16+12 = 28 фишек.
Кстати, если сделать запрос про второе взвешивание в духе
COINS_COUNT = 13
ALL_COINS = set(range(1,COINS_COUNT+1))    
ALL_STATES = ALL_COINS | {-s for s in ALL_COINS}
get_scale_strategy( ALL_STATES, 3, COINS_COUNT+16, 5 )

может быть окажется, что можно с 16+13 решить 13 -- это же всего 26 состояний, 27 исходов хватит. Вот 14 уже точно никак разрешить не получится.
То есть не выясненным остаётся только вопрос про 13 монет.
К сожалению комп сына сейчас далеко, так что придётся снова без бурт-форса прикинуть. Если первое взвешивание в задаче про 13 + дополнительные заведомо верные монеты будет 4х4, то в случае равенства останется 10 состояний на 9 возможных исходов.
И при неравенстве при взвешивании 5х5 останется 10 состояний. Ergo -- 12 -- точная верхняя оценка для числа монет, про которые ничего не известно, кроме, быть может, дополнительного запаса верных...

То есть единственный потенциал увеличения -- это 16 первых превратить в 18 и т. п.
Но и тут хочется, например, если есть 18 монет, участвовавших в первом неравновесном взвешивании, разбить их на три группы так, что бы 6 осталось на месте, 6 переехали на другую чашку и 6 вообще во втором не участвовали. Тогда за третье взвешивание нам надо будет выбрать из 6 монет-состояний, что не кажется нереальным.
Так что хочется сказать, что на последнее взвешивание можно прийти максимум с 3 состояниями, на предпоследнее с 9, на третье с конца -- 26, то есть
13 * 2 + 12 = 38 монет

1. 13 х 13. Если равенство, получаем 12 монет и 3 взвешивания. Мы это умеем!
Значит надо рассмотреть случай неравенства. Пусть левая чашка (монеты 1-13) тяжелее правой (монеты 14-26) .

2. взвешиваем: 1-5, 14-17 vs 9-13, 18-21 (а 6-8 и 22-26 откладываем в сторону )
При этом монеты бьются на три группы:
> Те, кто остался на той же чашке: 1-5 и 18-21 (9 шт)
< Те, кто переехал на другую чашку: 9-13 и 14-17 (9 шт)
= Те, кого отложили в сторону: 6-8 и 22-26 (8 шт)
В случае равенства получаем повтор ситуации: делим на группы 3, 2, 3 и дальше всё очевидно
Пусть, во втором взвешивании получили результат "правая тяжелее"
значит монета в группе тех, кто переехал (9-17)
Делим её на 3 группы относительно первого взвешивания (можно и относительно второго)
9, 10, 15 vs 14, 11, 12 (13, 16, 17)
> 9, 10, 14
< 11, 12, 15
= 13, 16, 17
и т. д.

Итого, за 4 взвешивания можно разобраться с 26 + 12 = 38 монетой.
С 40 не получится даже с запасом....
Все эмоциональные формулировки не соотвествуют действительному положению вещей и приведены мной исключительно "ради красного словца". За корректными формулировками и неискажённым изложением идей, следует обращаться к их автором или воспользоваться поиском
Re[3]: Задачке 45+ лет.
От: Vain Россия google.ru
Дата: 09.03.20 05:48
Оценка:
Здравствуйте, Erop, Вы писали:

E>Так?

E>1. 1+2+3+4 == 5+6+7+8 => фальшивая среди 9, 10, 11 ,12
E>2. 9 +10 == 1+2 => фальшивая среди 11 и 12
Зачем 1 и 2 взвешивать, если известно, что они уже не фальшивые? Взвешиваются те, что неизвестны. Известная примешивается из стопки, которая ещё не полностью проверена. Стопка 1,2,3,4 и 5,6,7,8 уже проверены на шаге 1.
Поэтому: 9 <=> 10
Если равно, то как раз и примешиваем 11: 9 <=> 11
Если нет, то примешиваем уже не фальшиваю из остатка, т.к. знаем, что фальшивых монет всегда одна:
К примеру: 9 < 10 -> 9 <=> 11, если весы 9 x 11 изменили баланс с < на >, соответственно, была фальшивой 9, т.к. 11 точно не фальшивая, если изменили с < на =, то фальшивая — 10.
[In theory there is no difference between theory and practice. In
practice there is.]
[Даю очевидные ответы на риторические вопросы]
Re[3]: Задачке 45+ лет.
От: Vain Россия google.ru
Дата: 09.03.20 06:02
Оценка:
Здравствуйте, Erop, Вы писали:

E>По моему тоже, но ты первый, кто тут смог сформулировать решение.

Моё решение тебе чем не подошло?
[In theory there is no difference between theory and practice. In
practice there is.]
[Даю очевидные ответы на риторические вопросы]
Re[4]: Задачке 45+ лет.
От: Erop Россия  
Дата: 10.03.20 07:32
Оценка:
Здравствуйте, Vain, Вы писали:

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


E>>Так?

E>>1. 1+2+3+4 == 5+6+7+8 => фальшивая среди 9, 10, 11 ,12
E>>2. 9 +10 == 1+2 => фальшивая среди 11 и 12
V>Зачем 1 и 2 взвешивать, если известно, что они уже не фальшивые?
Чтобы проверить те, про которые уже известно, если они и фальшивые, то тяжелее, но не известно фальшивые ли они.
Например, если у нас есть 8 монет из которых одна фальшивая и известно, что она тяжелее, то как за два взвешивания найти фальшивую?

V>Если равно, то как раз и примешиваем 11: 9 <=> 11

Это же не даёт экономии шагов? И так и так 2 шага получится?
Все эмоциональные формулировки не соотвествуют действительному положению вещей и приведены мной исключительно "ради красного словца". За корректными формулировками и неискажённым изложением идей, следует обращаться к их автором или воспользоваться поиском
Re[4]: Задачке 45+ лет.
От: Erop Россия  
Дата: 10.03.20 07:34
Оценка:
Здравствуйте, Vain, Вы писали:

V>Моё решение тебе чем не подошло?


Я уже не помню какое чьё, но мне так кажется, что твоё было то, которое для самого неудачного случая, позволяло установить фальшивую монету, но не позволяло узнать тяжелее она или легче...
Все эмоциональные формулировки не соотвествуют действительному положению вещей и приведены мной исключительно "ради красного словца". За корректными формулировками и неискажённым изложением идей, следует обращаться к их автором или воспользоваться поиском
Re[5]: Задачке 45+ лет.
От: Vain Россия google.ru
Дата: 10.03.20 16:23
Оценка:
Здравствуйте, Erop, Вы писали:

E>>>Так?

E>>>1. 1+2+3+4 == 5+6+7+8 => фальшивая среди 9, 10, 11 ,12
E>>>2. 9 +10 == 1+2 => фальшивая среди 11 и 12
V>>Зачем 1 и 2 взвешивать, если известно, что они уже не фальшивые?
E>Чтобы проверить те, про которые уже известно, если они и фальшивые, то тяжелее, но не известно фальшивые ли они.
У тебя первым взвешиванием на весах равно, значит нету там фальшивой монеты.

E>Например, если у нас есть 8 монет из которых одна фальшивая и известно, что она тяжелее, то как за два взвешивания найти фальшивую?

Задача про 12 монет и 3 взвешивание, и решение для этой задачи.

V>>Если равно, то как раз и примешиваем 11: 9 <=> 11

E>Это же не даёт экономии шагов? И так и так 2 шага получится?
Вот тут исправил: http://rsdn.org/forum/education/7677064
Автор: Vain
Дата: 10.03.20
[In theory there is no difference between theory and practice. In
practice there is.]
[Даю очевидные ответы на риторические вопросы]
Отредактировано 10.03.2020 17:02 Vain . Предыдущая версия .
Re[5]: Задачке 45+ лет.
От: Vain Россия google.ru
Дата: 10.03.20 16:59
Оценка:
Здравствуйте, Erop, Вы писали:

V>>Моё решение тебе чем не подошло?

E>Я уже не помню какое чьё, но мне так кажется, что твоё было то, которое для самого неудачного случая, позволяло установить фальшивую монету, но не позволяло узнать тяжелее она или легче...
А, не проверил последний вариант, тогда тот же подход:
o  o  o  o
z1 z2 z3 z4

(A)
o  o  x  o  o
z1 z2    z3 x1

(B)
o  o  x  o  o
z1 z3    z4 x1

монета | (A) | (B) 
-------+-----+-----
z1 > < | > < | > <
z2 > < | > < |  = 
z3 > < | > < | < >
z4 > < |  =  | < >

По изменении разности на весах можно понять которая меньше/больше.
[In theory there is no difference between theory and practice. In
practice there is.]
[Даю очевидные ответы на риторические вопросы]
Отредактировано 10.03.2020 17:04 Vain . Предыдущая версия .
Re[6]: Задачке 45+ лет.
От: Erop Россия  
Дата: 11.03.20 06:49
Оценка:
Здравствуйте, Vain, Вы писали:

V>У тебя первым взвешиванием на весах равно, значит нету там фальшивой монеты.

Так до него мы же не знаем, что нету

E>>Например, если у нас есть 8 монет из которых одна фальшивая и известно, что она тяжелее, то как за два взвешивания найти фальшивую?

V>Задача про 12 монет и 3 взвешивание, и решение для этой задачи.
Это я половину мысли пропустил. Я хотел написать, что ситуация в этой задаче отличается от нашей. И в нашем случае взвешивать неизвестную против заведомо правильной может иметь смысл...

V>>>Если равно, то как раз и примешиваем 11: 9 <=> 11

E>>Это же не даёт экономии шагов? И так и так 2 шага получится?
V>Вот тут исправил: http://rsdn.org/forum/education/7677064
Автор: Vain
Дата: 10.03.20


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

Я верно понял, что z1, z2, z3, z4 -- это 4 оставшиеся монеты после равенства в первом взвешивании, в x1 -- заведомо нефальшивая?

Мне, например, понятнее такая запись:

 (A) | (B) | монета 
-----+-----+--------
  <  |  <  | z1, <
  <  |  =  | z2, <
  <  |  >  | z3, >
  =  |  <  | z4, >
  =  |  =  | НЕВОЗМОЖНО
  =  |  >  | z4, <
  >  |  <  | z3, <
  >  |  =  | z2, >
  >  |  >  | z1, >


Но суть такая, что ответ и ты и я дали позже коллеги
Все эмоциональные формулировки не соотвествуют действительному положению вещей и приведены мной исключительно "ради красного словца". За корректными формулировками и неискажённым изложением идей, следует обращаться к их автором или воспользоваться поиском
Re[7]: Задачке 45+ лет.
От: Vain Россия google.ru
Дата: 11.03.20 09:46
Оценка:
Здравствуйте, Erop, Вы писали:

V>>У тебя первым взвешиванием на весах равно, значит нету там фальшивой монеты.

E>Так до него мы же не знаем, что нету

E>>>Например, если у нас есть 8 монет из которых одна фальшивая и известно, что она тяжелее, то как за два взвешивания найти фальшивую?

V>>Задача про 12 монет и 3 взвешивание, и решение для этой задачи.
E>Это я половину мысли пропустил. Я хотел написать, что ситуация в этой задаче отличается от нашей. И в нашем случае взвешивать неизвестную против заведомо правильной может иметь смысл...
У меня так и делается, ты невнимательно читал?

V>>>>Если равно, то как раз и примешиваем 11: 9 <=> 11

E>>>Это же не даёт экономии шагов? И так и так 2 шага получится?
V>>Вот тут исправил: http://rsdn.org/forum/education/7677064
Автор: Vain
Дата: 10.03.20

E>Ну, если я верно понял, что имеется в виду, то да, так получится. Но ты там тоже сравниваешь с заведомо нефальшивыми монетами...
Похоже на какой-то глюк (уже не в первый раз такое), делаешь изменения и они не отображаются. Только вот сейчас обновилось. Была правка тут: http://rsdn.org/forum/education/7642196
Автор: Vain
Дата: 24.01.20


E>И у тебя табличка немного непонятная.

У меня в каждой колонке по два значения

E>Но суть такая, что ответ и ты и я дали позже коллеги

Где?
[In theory there is no difference between theory and practice. In
practice there is.]
[Даю очевидные ответы на риторические вопросы]
Отредактировано 11.03.2020 9:50 Vain . Предыдущая версия .
Re[8]: Задачке 45+ лет.
От: Erop Россия  
Дата: 11.03.20 10:50
Оценка:
Здравствуйте, Vain, Вы писали:

V>У меня так и делается, ты невнимательно читал?

Мне кажется, что решений без таких взвешиваний вообще нет. Но ты писал (возможно и не ты, кстати ), что не имеет смысла взвешивать предположительно фальшивую против точно истинной. Мне этот тезис не понравился.

E>>Но суть такая, что ответ и ты и я дали позже коллеги

V>Где?
Ну ты вот там, где исправил. Я там, где написал, что не понимаю, о чём НИИ там неделю думал и т. д...


Это всё неинтересно. Интересно написать решалку задач такого типа для большего числа взвешиваний.
Например, про сколько монет можно определить какая фальшивая и тяжелее она или легче за 10 взвешиваний?
Все эмоциональные формулировки не соотвествуют действительному положению вещей и приведены мной исключительно "ради красного словца". За корректными формулировками и неискажённым изложением идей, следует обращаться к их автором или воспользоваться поиском
Re[9]: Задачке 45+ лет.
От: Vain Россия google.ru
Дата: 11.03.20 12:03
Оценка:
Здравствуйте, Erop, Вы писали:

V>>У меня так и делается, ты невнимательно читал?

E>Мне кажется, что решений без таких взвешиваний вообще нет. Но ты писал (возможно и не ты, кстати ), что не имеет смысла взвешивать предположительно фальшивую против точно истинной. Мне этот тезис не понравился.
Где?

E>>>Но суть такая, что ответ и ты и я дали позже коллеги

V>>Где?
E>Ну ты вот там, где исправил. Я там, где написал, что не понимаю, о чём НИИ там неделю думал и т. д...
Ещё выше написан принцип, по которому решается задача.

E>Это всё неинтересно. Интересно написать решалку задач такого типа для большего числа взвешиваний.

E>Например, про сколько монет можно определить какая фальшивая и тяжелее она или легче за 10 взвешиваний?
Ну если тебе нефиг делать, то можешь приступать.
[In theory there is no difference between theory and practice. In
practice there is.]
[Даю очевидные ответы на риторические вопросы]
Re[11]: Задачке 45+ лет.
От: NovaMind  
Дата: 22.03.20 08:14
Оценка:
Здравствуйте, Khimik, Вы писали:


E>>>Это всё неинтересно. Интересно написать решалку задач такого типа для большего числа взвешиваний.

E>>>Например, про сколько монет можно определить какая фальшивая и тяжелее она или легче за 10 взвешиваний?
V>>Ну если тебе нефиг делать, то можешь приступать.

K>За одно взвешивание получаем примерно полтора бита информации: либо левые весы тяжелее, либо правые, либо равенство — т.е. один из трёх вариантов.


K>3^10=59049


K>Это число надо поделить на два, поскольку есть дополнительный бит информации который надо определить — тяжелее или легче фальшивая монета:


K>59049/2=29524,5


K>Получается что ответ 29524 монеты. Правда тут наверняка реальное число меньше, поскольку не всегда можно равномерно разделить варианты. Из этого подхода получается что можно решить исходную задачу не только с 12, но и с 13 монетами, сомневаюсь что это возможно реально.


С 13-ю монетами можно решить.

Откладываем одну... (13-ю)
Решаем для 12-ти...

Если всё равно — "неправильная" 13-я.

Только не известно — легче или тяжелее....
 
Подождите ...
Wait...
Пока на собственное сообщение не было ответов, его можно удалить.