Задача для дата-сайентистов

Слож­ная задач­ка, готовь­тесь.

Под­ставь­те вме­сто букв циф­ры, что­бы полу­чи­лось вер­ное равен­ство:

ОДИН + ОДИН = МНОГО

Одна циф­ра — одна бук­ва. Это зна­чит, что нель­зя, напри­мер, чис­ло 5 заме­нить одно­вре­мен­но на бук­вы А и Б и наобо­рот.

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

Решение 1: логическое

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

1. Сна­ча­ла обра­ща­ем вни­ма­ние на коли­че­ство цифр: скла­ды­ва­ем два четы­рёх­знач­ных чис­ла и полу­ча­ем одно пяти­знач­ное, кото­рое начи­на­ет­ся с бук­вы М. Это зна­чит, что М = 1, ведь даже если мы возь­мём самое боль­шое четы­рёх­знач­ное чис­ло 9999 и сло­жим с самим собой, то полу­чим 19998, то есть всё рав­но будет еди­ни­ца в самом нача­ле.

👉 М = 1

2. Отсю­да же сле­ду­ет вывод, что О боль­ше или рав­но 5, пото­му что у нас уве­ли­чи­лось чис­ло раз­ря­дов в отве­те. Если бы О было 4 или мень­ше, то мы бы сло­жи­ли эти два четы­рёх­знач­ных чис­ла и в резуль­та­те тоже бы полу­чи­ли четы­рёх­знач­ное.

3. Смот­рим теперь на самые послед­ние сим­во­лы в каж­дом чис­ле: Н + Н = О. Когда скла­ды­ва­ют­ся два оди­на­ко­вых чис­ла, это то же самое, что умно­жить их на два. А при умно­же­нии на два мы все­гда полу­ча­ем чёт­ное чис­ло. Полу­ча­ет­ся, что О — чёт­ное, но из пунк­та 2 мы зна­ем, что О боль­ше или рав­но 5. Зна­чит, О = 6 или О = 8.

4. Теперь смот­рим на тре­тий раз­ряд наше­го сло­же­ния: Д + Д = О. Из тре­тье­го пунк­та мы зна­ем, что О — чёт­ное чис­ло, поэто­му И + И не дадут в сум­ме боль­ше 10 и еди­ни­ца не пере­не­сёт­ся в О. Это зна­чит, что И мень­ше 5.

5. А теперь самое слож­ное: у нас в раз­ря­дах есть Н + Н = О (пункт 3) и Д + Д = О. Так как циф­ры Д и Н — раз­ные, но в сум­ме дают оди­на­ко­вый резуль­тат О, то это зна­чит, что в каком-то одном слу­чае у нас полу­ча­ет­ся чис­ло боль­ше 10. Еди­ни­ца пере­но­сит­ся на дру­гой раз­ряд, а остав­ша­я­ся циф­ра будет оди­на­ко­вой.

6. Раз­ви­ва­ем мысль даль­ше. Из пунк­та 3 мы зна­ем, что О = 6 или О = 8. Полу­ча­ет­ся, что если О = 6, то Н = 3 (3 + 3 = 6) или Н = 8 (8 + 8 = 16). А если О = 8, то Н = 4 (4 + 4 = 8) или Н = 9 (9 + 9 = 18). Теперь под­ста­вим по оче­ре­ди каж­дое такое зна­че­ние и посмот­рим, что из это­го полу­чит­ся:

О = 6 Н = 3: зна­чит, Д долж­но быть рав­но 8, что­бы полу­чить 6 в пер­вом раз­ря­де. Про­ве­ря­ем:

Д + Д = О → 8 + 8 = 16 (да, а еди­ни­цу пере­но­сим)

Н + Н = О → 3 + 3 = 6 (да)

О + О (из нача­ла ОДИН + ОДИН) + 1 (пере­нес­ли еди­ни­цу из Д + Д) = 13 (в МНОГО М = 1, а Н = 3), зна­чит, О + О + 1 = 13 → О = 6 (всё сов­па­ло).

О = 6 Н = 8: зна­чит, Д долж­но быть рав­но 3.

Про­ве­ря­ем:

Д + Д = О → 3 + 3 = 6 (да)

Н + Н = О → 8 + 8 = 16 (да, а еди­ни­цу пере­но­сим)

О + О (из нача­ла ОДИН + ОДИН) = 13 (в МНОГО М = 1, а Н = 8), зна­чит, О + О = 18 → О = 9 (про­ти­во­ре­чие, у нас О = 6).

О = 8 Н = 4: зна­чит, Д долж­но быть рав­но 9, что­бы полу­чить 8 в пер­вом раз­ря­де. Про­ве­ря­ем:

Д + Д = О → 9 + 9 = 18 (да, а еди­ни­цу пере­но­сим)

Н + Н = О → 4 + 4 = 8 (да)

О + О (из нача­ла ОДИН + ОДИН) + 1 (пере­нес­ли еди­ни­цу из Д + Д) = 14 (в МНОГО М = 1, а Н = 4), зна­чит, О + О + 1 = 14 → О = 6,5 (про­ти­во­ре­чие, да и циф­ры не могут быть дроб­ны­ми).

О = 8 Н = 9: зна­чит, Д долж­но быть рав­но 4.

Про­ве­ря­ем:

Д + Д = О → 4 + 4 = 8 (да)

Н + Н = О → 9 + 9 = 18 (да, а еди­ни­цу пере­но­сим)

О + О (из нача­ла ОДИН + ОДИН) = 14 (в МНОГО М = 1, а Н = 9), зна­чит, О + О = 19 → О = 9,5 (про­ти­во­ре­чие, да и циф­ры не могут быть дроб­ны­ми).

👉 Полу­ча­ет­ся, что О = 6, Н = 3, а Д = 8.

7. Смот­рим на вто­рой раз­ряд: И + И = Г. Так как И мень­ше 5, а циф­ры 1 и 3 уже заня­ты, то И = 2 или И = 4. И не может быть нолём, пото­му что у нас не пере­но­сит­ся еди­ни­ца из Н + Н, а 0 + 0 = 0.

Если И = 2, то Г = 4, а если И = 4, то Г = 8. Но 8 у нас уже обо­зна­ча­ет­ся бук­вой Д, поэто­му И не может быть рав­но 4. Оста­ёт­ся вари­ант: И = 2, Г = 4.

👉 И = 2, Г = 4.

Под­став­ля­ем циф­ры вме­сто букв и полу­ча­ем пра­виль­ный ответ: 6823 + 6823 = 13646.

Если вы дочи­та­ли до кон­ца и не запу­та­лись в бук­вах и циф­рах — при­хо­ди­те в Прак­ти­кум. Если запу­та­лись — всё рав­но при­хо­ди­те, помо­жем разо­брать­ся.

Решение 2: грубый перебор

Тут вры­ва­ет­ся горе-программист. Он смот­рит на усло­вия зада­чи, и ему кажет­ся, что её мож­но решить про­стым пере­бо­ром. Так как он зав­тра­ка­ет не за рабо­чим ком­пью­те­ром, он откры­ва­ет кон­соль бра­у­зе­ра и пишет код на JavaScript:

1. Сра­зу завер­нем всё в функ­цию, что­бы когда нашлось нуж­ное зна­че­ние, про­сто вый­ти из неё. И сра­зу её запус­ка­ем, что­бы код испол­нял­ся:

function calculate_this_shit(){ }

calculate_this_shit();

2. Какие нам нуж­ны пере­мен­ные? Назо­вем их бук­ва­ми:

function calculate_this_shit(){

var o, d, i, n, m, g;

}

calculate_this_shit();

3. Мож­но было бы как-то по-умному все эти бук­вы пере­би­рать в мас­си­ве, но мне лень. Я хочу про­сто пере­брать их шестью вло­жен­ны­ми друг в дру­га цик­ла­ми, исполь­зуя гру­бую копи­пас­ту. Смысл в том, что мы пере­би­ра­ем циф­ры от 0 до 9 и про­ве­ря­ем наши зна­че­ния на соот­вет­ствие усло­ви­ям зада­чи. Что­бы про­ве­рить их на соот­вет­ствие, мы умно­жа­ем, напри­мер, бук­ву О на 1000, бук­ву Д на 100, бук­ву И на 10 и бук­ву Н на еди­ни­цу. И так же с пра­вой частью.

function calculate_this_shit() {
  var o, d, i, n, m, g;
  for (o = 0; o < 10; o++) {
    for (d = 0; d < 10; d++) {
      for (i = 0; i < 10; i++) {
        for (n = 0; n < 10; n++) {
          for (m = 0; m < 10; m++) {
            for (g = 0; g < 10; g++) {
              var left = o * 1000 + d * 100 + i * 10 + n * 1;
              var right = m * 10000 + n * 1000 + o * 100 + g * 10 + o;
              if (2 * left == right && right > 999) {
                return ('Выражение: ' + left + ' + ' + left + ' = ' + right);
              }
            }
          }
        }
      }
    }
  }
}
calculate_this_shit();

Если запу­стить этот код, мы полу­чим резуль­тат:

Выражение: 6803 + 6803 = 13606

Тут нару­ше­но усло­вие, что каж­дой бук­ве долж­на быть при­сво­е­на своя циф­ра. А у нас два раза встре­ча­ет­ся ноль: на бук­ве И и на бук­ве Г. Зна­чит, нужен такой алго­ритм:

  1. Когда урав­не­ние сов­па­ло, нуж­но затол­кать все бук­вы в мас­сив.
  2. Отсор­ти­ро­вать этот мас­сив по воз­рас­та­нию или убы­ва­нию.
  3. Про­ве­рить, нет ли в мас­си­ве повто­ров.
  4. И толь­ко если нет — раз­ре­шить выдать резуль­тат. А если повто­ры есть — искать даль­ше.

Неохо­та сей­час писать само­му все эти про­вер­ки, поэто­му берем код со Стек-оверфлоу:

if (2 * left == right && right > 999) {
  // По умолчанию ставим флаг, что дубликатов нет
  var foundDuplicate = false;
  // Заталкиваем наши буквы в массив
  var all = [o, d, i, n, m, g];
  // Сортируем массив
  var sorted_all = all.slice().sort();
  // Перебираем массив в поисках дубликатов
  for (let i = 0; i < sorted_all.length - 1; i++) {
    if (sorted_all[i + 1] == sorted_all[i]) {
      // Если дубликат найден, ставим флаг
      var foundDuplicate = true;
    }
  }
  //И только если флаг не стоит...
  if (foundDuplicate == false) {
    return ('Выражение: ' + left + ' + ' + left + ' = ' + right);
  }
}

Теперь будет рабо­тать. Ито­го­вый код в рас­хло­пе:

Итоговый код
function calculate_this_shit() {
  var o, d, i, n, m, g;
  for (o = 0; o < 10; o++) {
    for (d = 0; d < 10; d++) {
      for (i = 0; i < 10; i++) {
        for (n = 0; n < 10; n++) {
          for (m = 0; m < 10; m++) {
            for (g = 0; g < 10; g++) {
              var left = o * 1000 + d * 100 + i * 10 + n * 1;
              var right = m * 10000 + n * 1000 + o * 100 + g * 10 + o;
              if (2 * left == right && right > 999) {
                var foundDuplicate = false;
                var all = [o, d, i, n, m, g];
                var sorted_all = all.slice().sort();
                for (let i = 0; i < sorted_all.length - 1; i++) {
                  if (sorted_all[i + 1] == sorted_all[i]) {
                    var foundDuplicate = true;
                  }
                }
                if (foundDuplicate == false) {
                  return ('Выражение: ' + left + ' + ' + left + ' = ' + right);
                }

              }
            }
          }

        }
      }
    }
  }
}
calculate_this_shit();