Задачи на рассуждения

Мы часто пуб­ли­ку­ем зада­чи раз­ной сте­пе­ни слож­но­сти. Сего­дня — под­бор­ка самых инте­рес­ных и объ­еди­нён­ных одной иде­ей. Для реше­ния этих задач потре­бу­ет­ся вни­ма­тель­но рас­суж­дать и при­ме­нять логи­ку.

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

Лишняя тысяча

Один зав­хоз нашёл на скла­де неучтён­ные шины и отпра­вил под­чи­нён­но­го Семё­на про­дать 4 коле­са за 50 тысяч. Семён нашёл двух поку­па­те­лей, одно­му были нуж­ны перед­ние колё­са, а дру­го­му — зад­ние. Семён имел ком­мер­че­скую жил­ку, поэто­му про­дал колё­са не за 50, а за 55 тысяч: каж­дый поку­па­тель запла­тил по 27 500 руб­лей, на 2500 боль­ше, чем нуж­но.

Доволь­ный, он вер­нул­ся к зав­хо­зу и рас­ска­зал об удач­ной про­да­же. Но началь­ник решил про­явить прин­ци­пи­аль­ность и отпра­вил Семё­на вер­нуть по 2500 каж­до­му поку­па­те­лю.

А Семён решил схит­рить: отдал каж­до­му по тыся­че, а три оста­вил себе. Полу­ча­ет­ся, что каж­дый поку­па­тель запла­тил не 27 500, а 26 500. Идёт Семён и счи­та­ет в уме: «26 500 + 26 500 = 53 000 — запла­ти­ли за колё­са, и ещё 3000 у меня оста­лось.

Ито­го 53 000 + 3 000 = 56 000. А про­дал я за 55 000. Любо­пыт­но».

Отку­да взя­лась лиш­няя тыся­ча?

РЕШЕНИЕ

Ошиб­ка в том, что Семён скла­ды­ва­ет сум­мы от раз­ных сде­лок. Пра­виль­ные вычис­ле­ния будут выгля­деть так:

27 500 + 27 500 = 55 000 — полу­че­но после про­да­жи колёс.

5000 — зав­хоз ска­зал вер­нуть поку­па­те­лям, из них Семён:

2000 — отдал,

3000 — забрал себе.

Как видим, лиш­ней тыся­чи нигде нет.

Есть и дру­гой спо­соб: най­ти ошиб­ку в вычис­ле­ни­ях Семё­на.

26 500 + 26 500 = 53 000 — запла­ти­ли поку­па­те­ли за колё­са, хотя долж­ны были запла­тить 50 000, как хотел зав­хоз.

53 000 − 50 000 = 3000 — лиш­ние день­ги, кото­рые Семён и взял себе.

Ошиб­ка в вычис­ле­ни­ях Семё­на в том, что нуж­но эти три тыся­чи не при­бав­лять, а отни­мать, тогда и полу­чит­ся нуж­ная сум­ма в 50 000, кото­рую полу­чил зав­хоз.

Друзья в боулинге

Три дру­га в пят­ни­цу вече­ром пошли поиг­рать в боулинг и за три часа запла­ти­ли 4500 руб­лей — каж­дый ски­нул­ся по пол­то­ры тыся­чи. Когда они вышли, то встре­ти­ли ещё одно­го дру­га — дирек­то­ра это­го клу­ба. Он узнал, что ребя­та запла­ти­ли пол­ную сто­и­мость за игру, и ска­зал: «Подо­жди­те, я вам сде­лаю скид­ку, сей­час кас­сир вер­нёт вам лиш­нее».

Кас­сир полу­чил зада­ние спу­стить­ся и вер­нуть дру­зьям пол­то­ры тыся­чи, но он решил отдать им толь­ко 900 руб­лей, а 600 оста­вил себе. В ито­ге полу­ча­ет­ся, что каж­дый из дру­зей полу­чил назад по 300 руб­лей и запла­тил за боулинг по 1200. Но тогда выхо­дит, что они втро­ём запла­ти­ли за игру 3600 руб­лей, и ещё 600 у нечест­но­го кас­си­ра, а в сум­ме это все­го 4200. Где ещё 300 руб­лей?

РЕШЕНИЕ

Если вы не чита­ли про­шлую зада­чу и види­те такие зада­чи впер­вые — вни­ма­тель­но сле­ди­те за ходом мыс­ли.

Ошиб­ка в зада­че в том, что нель­зя скла­ды­вать 600 руб­лей, кото­рые забрал кас­сир себе, и 3600, кото­рые запла­ти­ли за игру ребя­та. Вме­сто это­го давай­те сна­ча­ла про­ве­рим, все ли день­ги у нас на месте.

Счи­та­ем: дру­зья запла­ти­ли сна­ча­ла 4500, но дирек­тор отдал им 1500, поэто­му боулинг-клуб зара­бо­тал 3000, а пол­то­ры тыся­чи взял кас­сир и понёс ребя­там. По пути он забрал 600, а 900 отдал им: 600 + 900 = 1500. Пока всё вер­но.

Ито­го: 3000 в кас­се клу­ба, 600 руб­лей у кас­си­ра, а дру­зья запла­ти­ли 3600. Полу­ча­ет­ся, что из денег дру­зей кас­сир забрал себе 600 руб­лей, а осталь­ное оста­лось в кас­се. Всё схо­дит­ся.

Мошенник с Айфоном

Один тор­го­вец через сайт объ­яв­ле­ний про­да­ёт очень ста­рый Айфон за 2000 руб­лей. К нему при­е­хал поку­па­тель, у кото­ро­го с собой толь­ко пяти­ты­сяч­ная купю­ра. Тор­го­вец берёт её, идёт к сосе­ду и про­сит раз­ме­нять, в ито­ге полу­ча­ет от сосе­да 2 купю­ры по 2000 и одну тыся­че­руб­лёв­ку.

Поку­па­тель заби­ра­ет Айфон, 3000 руб­лей сда­чи и уез­жа­ет. А через пол­ча­са при­бе­га­ет злой сосед и гово­рит, что наш про­да­вец дал ему фаль­шив­ку. Что­бы решить вопрос мир­но, тор­го­вец отдал сосе­ду 5000 руб­лей из сво­их денег, а потом заду­мал­ся: сколь­ко он сего­дня поте­рял?

РЕШЕНИЕ

Ино­гда эту зада­чу реша­ют так:

  • 2000 ушло поку­па­те­лю в виде Айфо­на.
  • 3000 ушло к нему же как сда­ча.
  • 5000 при­шлось отдать сосе­ду за фаль­ши­вую купю­ру.
  • Ито­го 2000 + 3000 + 5000 = 10 000.

Но это невер­но. Давай­те раз­бе­рём­ся, как рас­пре­де­ли­лись день­ги на самом деле.

Для нача­ла нуж­но отве­тить на вопрос, что мы вооб­ще счи­та­ем. Тут два вари­ан­та:

  • Мы можем счи­тать толь­ко поте­ри налич­ных денег. Напри­мер, Айфон у нас настоль­ко ста­рый, что для про­дав­ца он сто­ит 0 ₽. Пред­ставь­те, что про­да­ёт­ся не Айфон, а какой-нибудь ста­рый шкаф, кото­рый выгод­нее даже отдать бес­плат­но, чем само­сто­я­тель­но выво­зить на свал­ку. В этом слу­чае поте­ря Айфо­на — это 0 ₽.
  • Или же мы можем счи­тать, что Айфон — тоже часть поте­ри и для про­дав­ца он сто­ит те же 2000 ₽. Тогда про­да­жа Айфо­на учи­ты­ва­ет­ся в общих рас­чё­тах.

Что­бы теперь рас­счи­тать любой из вари­ан­тов, про­сто запи­шем все опе­ра­ции в стол­бик с точ­ки зре­ния про­дав­ца. Там, где ему что-то при­бы­ло, мы напи­шем это со зна­ком плюс, убы­ло — со зна­ком минус. Полу­чит­ся жур­нал дви­же­ния денег и экви­ва­лен­тов, по-программистски — лог:

Что сделал продавец Движение денег и эквивалентов
Отдал Айфон (− 2000 ₽)
Получил фальшивку + 0 ₽
Отдал фальшивку на размен − 0 ₽
Получил размен + 5000 ₽
Отдал сдачу − 3000 ₽
Вернул деньги соседу − 5000 ₽
Итого − 3000 ₽ (− 5000 ₽)

Полу­ча­ет­ся, что в зави­си­мо­сти от наше­го взгля­да про­да­вец лишил­ся либо трёх тысяч руб­лей чистых денег, либо това­ра и денег на общую сум­му пять тысяч руб­лей. Логи­ро­ва­ние собы­тий — вели­кая вещь!

Баг или фича? В рабо­те у про­грам­ми­ста есть про­ект, в кото­ром нуж­но пофик­сить три бага и доба­вить три фичи. За час про­грам­мист может пофик­сить 1–2 бага или доба­вить 1–2 фичи. Но он посто­ян­но отвле­ка­ет­ся на фору­мы и соц­се­ти, поэто­му каж­дый час рабо­та идёт так:

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

Сколь­ко мини­маль­но вре­ме­ни потре­бу­ет­ся про­грам­ми­сту, что­бы сдать про­ект без багов и с пустым тре­ке­ром задач?

РЕШЕНИЕ

Един­ствен­ное дей­ствие, при кото­ром не появ­ля­ет­ся новых багов и фич — это когда про­грам­мист за час добав­ля­ет сра­зу две фичи. Полу­ча­ет­ся, что для успеш­но­го завер­ше­ния нуж­но сде­лать чёт­ное коли­че­ство фич под­ряд — 2, 4, 6, 8 или что-то подоб­ное.

Полу­ча­ет­ся, что зада­ча про­грам­ми­ста — сво­и­ми дей­стви­я­ми как мож­но быст­рее прий­ти к тому, что­бы в про­ек­те оста­лись нена­пи­сан­ны­ми толь­ко фичи и что­бы их чис­ло дели­лось на 2. На стар­те ему нуж­но сде­лать 3 фичи, зна­чит, новая цель — из трёх багов полу­чить нечёт­ное коли­че­ство фич-заданий в тре­ке­ре. В ито­ге это даст про­грам­ми­сту их чёт­ное коли­че­ство, и он их попар­но выпол­нит.

Нечёт­ное коли­че­ство фич — это 1, 3, 5 и так далее. Если мы закро­ем сра­зу два бага, то это даст нам толь­ко одну новую фичу в тре­ке­ре, и оста­нет­ся ещё один баг. Дела­ем это за пер­вый час.

Исход­ные дан­ные: 3 бага, 3 фичи.

Час 1: 1 баг, 4 фичи (пофик­си­ли 2 бага, полу­чи­ли +1 фичу в тре­ке­ре).

У нас появи­лось чёт­ное коли­че­ство фич, кото­рые мож­но сра­зу попар­но закрыть. Тра­тим ещё 2 часа.

Час 2: 1 баг, 2 фичи (реа­ли­зо­ва­ли сра­зу 2 фичи, новых зада­ний не появи­лось).

Час 3: 1 баг (реа­ли­зо­ва­ли сра­зу 2 фичи, новых зада­ний не появи­лось).

Уже хоро­шо. Теперь един­ствен­ное, что оста­ёт­ся про­грам­ми­сту — отра­бо­тать этот баг.

Час 4: 2 бага (пофик­си­ли 1 баг, полу­чи­ли 2 новых).

А вот тут мож­но попасть в ловуш­ку, если сра­зу пофик­сить 2 бага и полу­чить фичу. Дело в том, что если оста­ёт­ся толь­ко одна фича, то после её выпол­не­ния в тре­ке­ре появ­ля­ет­ся запись, что нуж­но сде­лать ещё одну. Полу­ча­ет­ся бес­ко­неч­ный цикл. Зна­чит, нам нуж­но фик­сить по одно­му багу по оче­ре­ди.

Час 5: 3 бага (пофик­си­ли 1 баг, полу­чи­ли 2 новых).

Ага, у нас уже 3 бага, а это зна­чит, что мож­но сде­лать одно­вре­мен­но 2 из них и не попасть потом в замкну­тый круг. Про­ве­рим.

Час 6: 1 баг, 1 фича (пофик­си­ли 2 бага, полу­чи­ли +1 фичу в тре­ке­ре).

Но мы уже встре­ча­ли ситу­а­цию, когда был толь­ко один баг, и зна­ем, как из него полу­чить 2, а из двух — фичу. Дела­ем.

Час 7: 2 бага, 1 фича (пофик­си­ли 1 баг, полу­чи­ли 2 новых).

Час 8: 2 фичи (пофик­си­ли 2 бага, полу­чи­ли +1 фичу в тре­ке­ре).

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

Час 9: всё сде­ла­но (реа­ли­зо­ва­ли сра­зу 2 фичи, новых зада­ний не появи­лось).

Ответ: про­грам­ми­сту потре­бу­ет­ся мини­мум 9 часов.