Задать вопрос
@nimbus214

Как это быстро сделать?

Надо сделать так, чтобы цифры, присваиваемые буквам все были различными, думаю если увидите код, поймёте о чём я спрашиваю. Это можно сделать перебором, но мне интересно, можно ли сделать как то быстрее.
#include <iostream>
using namespace std;
int main()
{
    int dedka, babka, repka;
    long int skazka;
    cout << "s" << endl;
    for (int d = 0; d < 10; d++) {
        for (int e = 0; e < 10; e++) {
            for (int k = 0; k < 10; k++) {
                for (int a = 0; a < 10; a++) {
                    for (int b = 0; b < 10; b++) {
                        for (int r = 0; r < 10; r++) {
                            for (int p = 0; p < 10; p++) {
                                for (int s = 0; s < 10; s++) {
                                    for (int k = 0; k < 10; k++) {
                                        for (int z = 0; z < 10; z++) {
                                            dedka = d * 10000 + e * 1000 + d * 100 + k * 10 + a;
                                            babka = b * 10000 + a * 1000 + b * 100 + k * 10 + a;
                                            repka = r * 10000 + e * 1000 + p * 100 + k * 10 + a;
                                            skazka = s * 100000 + k * 10000 + a * 1000 + z * 100 + k * 10 + a;
                                            if ((dedka + babka + repka == skazka) && ((dedka > babka) && (babka > repka)) && ((dedka > 9999)&& (babka > 9999)&& (repka > 9999)&& (skazka > 99999))) {
                                                cout << dedka << " + " << babka << " + " << repka << " = " << skazka << endl;
                                            }
                                        }
                                    }
                                }
                            }
                        }
                    }
                }
            }
        }
    }
    return 0;
}
  • Вопрос задан
  • 138 просмотров
Подписаться 1 Простой 4 комментария
Пригласить эксперта
Ответы на вопрос 2
Rsa97
@Rsa97
Для правильного вопроса надо знать половину ответа
Надо решить как можно больше аналитически.
a + a + a = ...a
Это возможно только при a = 0 или a = 5.
k + k + k = ...k при a = 0 или k + k + k + 1 = ...k при a = 5
Эта система имеет решение только при a = 0 и k = 5.
s - это перенос из младшего разряда. Значит s ∈ {1, 2}.
e + 0 + e = ...0 или e + 0 + e + 1 = ...0 или e + 0 + e + 2 = ...0
Такое возможно только при e ∈ {0, 4, 5, 9}. Но 0 и 5 уже заняты. Значит e ∈ {4, 9}.
Получаем
int a = 0;
int k = 5;
for (int s = 1; s <= 2; s++) {
  for (int e = 4; e <= 9; e += 5) {
    ...Тут все остальные буквы.

Такой анализ даст сокращение полного перебора в 2500 раз.
Затем, можно сказать, что d > b > r, соответственно записать циклы как
...
    for (int d = 3; d <= 9; d++) {
      for (int b = 2; b < d; b++) {
        for (int r = 1; r < b; r++) {
          ...

Это сократит перебор ещё почти в 12 раз (с 1000 циклов до 84)
Для p, с учётом, что из младшего разряда переносится 1, а в старший должна уйти 2, можно записать условие
d + b + p + 1 >= 20 => p >= 19 - d - b
Значит получим цикл
...
          for (int p = 19 - d - b; p <= 9; p++) {
            ...

z можно вообще не оборачивать в цикл, а вычислять как z = (d + b + p + 1) % 10.
Это уменьшит перебор ещё в 10 раз.
Ну и, как правило, в таких задачах есть условие, что разным буквам соответствуют разные цифры. Стоит добавить проверку там, где это необходимо.
Суммарно перебор сократится более, чем в 300000 раз.
Решение на PHP

<?php
$a = 0;
$k = 5;
$count = 0;
for ($s = 1; $s <= 2; $s++) {
  for ($e = 4; $e <= 9; $e += 5) {
    for ($d = 3; $d <= 9; $d++) {
      if ($d == 5 || $d == $e) {
        continue;
      }
      for ($b = 2; $b < $d; $b++) {
        if ($b == 5 || $b == $s || $b == $e) {
          continue;
        }
        for ($r = 1; $r < $b; $r++) {
          if ($r == 5 || $r == $s || $r == $e) {
            continue;
          }
          for ($p = 19 - $d - $b; $p <= 9; $p++) {
            if ($p == 5 || $p == $s || $p == $e || 
                $p == $d || $p == $b || $p == $r) {
              continue;
            }
            $z = ($d + $b + $p + 1) % 10;
            if ($z == 0 || $z == 5 || $z == $s || 
                $z == $e || $z == $d || $z == $b || 
                $z == $r || $z == $p) {
              continue;
            }
            $count += 1;
            $dedka = $d * 10100 + $e * 1000 + 50;
            $babka = $b * 10100 + 50;
            $repka = $r * 10000 + $e * 1000 + $p * 100 + 50;
            $skazka = $s * 100000 + $z * 100 + 50050;
            if ($dedka + $babka + $repka == $skazka) {
              print " {$dedka}\n+{$babka}\n+{$repka}\n======\n{$skazka}\n";
            }
          }
        }
      }
    }
  }
}
print "count = {$count}\n";
/*
 94950
+80850
+74350
======
250150
count = 17
*/


Фактически, проверка основного условия выполнилась только 17 раз вместо 1000000000 в вашем случае.

P.S. Да, и s можно тоже не перебирать, а вычислять. Тогда будет ещё быстрее, основная проверка выполнится 11 раз.
Ответ написан
Комментировать
wataru
@wataru Куратор тега C++
Разработчик на С++, экс-олимпиадник.
Перебирайте буквы от младших к старшим: a,k, d,b,z, e...

Проверяйте правильность суммы поциферно справа на-лево как можно раньше.

Т.е. после перебора a уже можно проверить, что (a+a+a) % 10 = a. Потом, после k надо проверить (ka+ka+ka)%100 = ka, после dbz можно проверить третью цифру.

Можно немного соптимизировтаь, есл ине считать (ка+ка+ка)%100, а помнить, какой там перенос из младшей цифры и проверять уже только (k+k+k+carry1)%10 = k, carry2 = (k+k+k+carry1)/10; Потом проверить, что (d+b+p + carry2)%10 = z и т.д.

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

Следующее улучшение - не перебирать буквы s, z, e и r, а сразу считать, какими они должны быть, чтобы сумма сходилась. С s и z все тривиально, а для e и r надо чуть-чуть математики.

Это надо аккуратно выписать уравнения вида (e+a+e+carry2)%10=a.

Тут надо применить свойства модуля: 2e %10=-carry2 % 10, Тут для e есть 2 решения, если carry2 четно: (10-carry2)/2, (20-carry2) / 2

Но это улучшение не сильно ускорит.
Ответ написан
Ваш ответ на вопрос

Войдите, чтобы написать ответ

Похожие вопросы