[Архив!] Чистая математика, физика, химия и т.п.: задачки для тренировки мозгов, никак не связанные с торговлей - страница 510

 
IgorM:
не люблю пользоваться операторами continue и break, но может быть чем нибудь помогут Вам, тем более 36-кратное вложение if на mql может и "не прокатить"
Если не прокатило бы, то воспользовался бы continue... Но что-то не хочется Мне вообще с этим возиться. Лучше уж другой алгоритм реализовать, хоть интересно будет.
 
MaxZ:

А ускорить Мой код можно разбив if, состоящий из сложного 36-кратного проверочного условия, на 36 if-ов с простым условием! :)))

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

Я твой код запускал в MT5. В нём короткие вычисления логических операторов уже реализованы (встроены), так что смысл дробить код на множество ифов отсутствует.

В MT4 другое дело, там эта оптимизация имеет смысл. Но оценку времени я проводил в MT5, по короткой схеме.

 

Ускорил в 4 раза. Переписал Validate().

Теперь так:

bool Validate(int X)
  {
   int XX=0;
   int A[];
   IntToArray(X,A);
   for(int i=5;i>-1;i--)
     {
      XX|=int(1<<A[i]);
     }
   if(XX==0x7E) {return true;}
   return false;
  }
void IntToArray(int X, int &A[])
{
  ArrayResize(A,6);
  for(int i=0;i<6;i++)
    {
     A[i]=X%10; X/=10;
    }
}
WorkTime == 200 ms
 

Ужасно, но есть смысл оптимизировать код следующим образом. В разы быстрее! И тут уже MT5 не поможет.

Это конечно не идея. Но интересно как быстро сработает! :))

Также в коде уменьшил диапазон значений делителя. 654321/2 = 327160,5...

for (int A6 = 1; A6 <= 6; A6++)
   for (int A5 = 1; A5 <= 6; A5++)
   {
      if (A5 == A6) continue;
      for (int A4 = 1; A4 <= 6; A4++)
      {
         if (A4 == A5 || A4 == A6) continue;
         for (int A3 = 1; A3 <= 6; A3++)
         {
            if (A3 == A4 || A3 == A5 || A3 == A6) continue;
            for (int A2 = 1; A2 <= 6; A2++)
            {
               if (A2 == A3 || A2 == A4 || A2 == A5 || A2 == A6) continue;
               for (int A1 = 1; A1 <= 6; A1++)
               {
                  if (A1 == A2 || A1 == A3 || A1 == A4 || A1 == A5 || A1 == A6) continue;
for (int B6 = 1; B6 <= 3; B6++)
{
   if (B6 == A6) continue;
   for (int B5 = 1; B5 <= 6; B5++)
   {
      if (B6 == 3 && B5 > 2) continue;
      if (B5 == A5) continue;
      if (B5 == B6) continue;
      for (int B4 = 1; B4 <= 6; B4++)
      {
         if (B4 == A4) continue;
         if (B4 == B5 || B4 == B6) continue;
         for (int B3 = 1; B3 <= 6; B3++)
         {
            if (B3 == A3) continue;
            if (B3 == B4 || B3 == B5 || B3 == B6) continue;
            for (int B2 = 1; B2 <= 6; B2++)
            {
               if (B2 == A2) continue;
               if (B2 == B3 || B2 == B4 || B2 == B5 || B2 == B6) continue;
               for (int B1 = 1; B1 <= 6; B1++)
               {
                  if (B1 == A1) continue;
                  if (B1 == B2 || B1 == B3 || B1 == B4 || B1 == B5 || B1 == B6) continue;
                  
                  int A = A6*100000+A5*10000+A4*1000+A3*100+A2*10+A1;
                  int B = B6*100000+B5*10000+B4*1000+B3*100+B2*10+B1;
                  if (MathMod(A, B) == 0)
                  Print(A6,A5,A4,A3,A2,A1,"/",B6,B5,B4,B3,B2,B1,"=",A/B);
               }
            }
         }
      }
   }
}
               }
            }
         }
      }
   }
 
MetaDriver:

Ускорил в 4 раза. Переписал Validate().

Теперь так:

WorkTime == 200 ms

Красиво получилось! Не то что у Меня.

Есть идея написать алгоритм деления в столбик. Делить по разрядно, записывать остатки от деления и при совпадении или результате большем, чем 6, делать операцию continue. Я именно этот и делал сегодня днём, когда перебирал пятёрку, делил всё в столбик. Но это на долго! :))

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

 
MaxZ:

Есть идея написать алгоритм деления в столбик. Делить по разрядно, записывать остатки от деления и при совпадении или результате большем, чем 6, делать операцию continue. Я именно этот и делал сегодня днём, когда перебирал пятёрку, делил всё в столбик. Но это на долго! :))

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

О! Идея неплохая. Ещё раз переписал. WorkTime=125 ms

bool Validate(int X)
  {
   int XX=0;
   int A[];
   if(!IntToArray(X,A)) return false; // изменено здесь тоже, но основное ниже
   for(int i=5;i>-1;i--)
     {
      XX|=int(1<<A[i]);
     }
   if(XX==0x7E) {return true;}
   return false;
  }
bool IntToArray(int X,int &A[])
  {
   ArrayResize(A,6);
   int x=X%10;
   if(x==0 || x>6) return false;  // главное изменение
   else A[0]=x;
   for(int i=1;i<6;i++)
     {
      X/=10;
      x=X%10;
      if(x==0 || x>6) return false;  // главное изменение
      else A[i]=x;
     }
    return true;
  }
 
MetaDriver:

О! Идея неплохая. Ещё раз переписал. WorkTime=125 ms

Теперь хоккеисты точно счастливы останутся! :)))) Хотя Я имел ввиду не именно это! ;D


А сколько счётчик времени показывает по Моему коду?


Мне изменения понятны. Я только вот это не осилил пока:

   for(int i=5;i>-1;i--)
     {
      XX|=int(1<<A[i]);
     }
   if(XX==0x7E) {return true;}

"|=" - логическое "ИЛИ"? А вот дальше полный тупик...

 
MaxZ:
Теперь хоккеисты точно счастливы останутся! :))))

Ага.

Твой новый код работает ещё быстрее, однако там есть косяки.

for (int A6 = 1; A6 <= 6; A6++)
   for (int A5 = 1; A5 <= 6; A5++)
   {
      if (A5 == A6) continue;
      for (int A4 = 1; A4 <= 6; A4++)
      {
         if (A4 == A5 || A4 == A6) continue;
         for (int A3 = 1; A3 <= 6; A3++)
         {
            if (A3 == A4 || A3 == A5 || A3 == A6) continue;
            for (int A2 = 1; A2 <= 6; A2++)
            {
               if (A2 == A3 || A2 == A4 || A2 == A5 || A2 == A6) continue;
               for (int A1 = 1; A1 <= 6; A1++)
               {
                  if (A1 == A2 || A1 == A3 || A1 == A4 || A1 == A5 || A1 == A6) continue;
for (int B6 = 1; B6 <= 3; B6++)
{
   if (B6 == A6) continue;
   for (int B5 = 1; B5 <= 6; B5++)
   {
      if (B6 == 3 && B5 > 2) continue;
      if (B5 == A5) continue;
      if (B5 == B6) continue;
      for (int B4 = 1; B4 <= 6; B4++)
      {
         if (B4 == A4) continue;
         if (B4 == B5 || B4 == B6) continue;
         for (int B3 = 1; B3 <= 6; B3++)
         {
            if (B3 == A3) continue;
            if (B3 == B4 || B3 == B5 || B3 == B6) continue;
            for (int B2 = 1; B2 <= 6; B2++)
            {
               if (B2 == A2) continue;
               if (B2 == B3 || B2 == B4 || B2 == B5 || B2 == B6) continue;
               for (int B1 = 1; B1 <= 6; B1++)
               {
                  if (B1 == A1) continue;
                  if (B1 == B2 || B1 == B3 || B1 == B4 || B1 == B5 || B1 == B6) continue;
                  
                  int A = A6*100000+A5*10000+A4*1000+A3*100+A2*10+A1;
                  int B = B6*100000+B5*10000+B4*1000+B3*100+B2*10+B1;
                  if (MathMod(A, B) == 0)
                  Print(A6,A5,A4,A3,A2,A1,"/",B6,B5,B4,B3,B2,B1,"=",A/B);
               }
            }
         }
      }
   }
}
               }
            }
         }
      }
   }

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

Объясни смысл выделенных строчек. Не догоняю.

 
MetaDriver:

Ага.

Твой новый код работает ещё быстрее, однако там есть косяки.

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

Объясни смысл выделенных строчек. Не догоняю.

Точно... Бред! :))) А со скобками вроде норма, копировал с готового кода.

Надо так:

for (int A6 = 1; A6 <= 6; A6++)
   for (int A5 = 1; A5 <= 6; A5++)
   {
      if (A5 == A6) continue;
      for (int A4 = 1; A4 <= 6; A4++)
      {
         if (A4 == A5 || A4 == A6) continue;
         for (int A3 = 1; A3 <= 6; A3++)
         {
            if (A3 == A4 || A3 == A5 || A3 == A6) continue;
            for (int A2 = 1; A2 <= 6; A2++)
            {
               if (A2 == A3 || A2 == A4 || A2 == A5 || A2 == A6) continue;
               for (int A1 = 1; A1 <= 6; A1++)
               {
                  if (A1 == A2 || A1 == A3 || A1 == A4 || A1 == A5 || A1 == A6) continue;
for (int B6 = 1; B6 <= 3; B6++)
   for (int B5 = 1; B5 <= 6; B5++)
   {
      if (B6 == 3 && B5 > 2) continue;
      if (B5 == B6) continue;
      for (int B4 = 1; B4 <= 6; B4++)
      {
         if (B4 == B5 || B4 == B6) continue;
         for (int B3 = 1; B3 <= 6; B3++)
         {
            if (B3 == B4 || B3 == B5 || B3 == B6) continue;
            for (int B2 = 1; B2 <= 6; B2++)
            {
               if (B2 == B3 || B2 == B4 || B2 == B5 || B2 == B6) continue;
               for (int B1 = 1; B1 <= 6; B1++)
               {
                  if (B1 == B2 || B1 == B3 || B1 == B4 || B1 == B5 || B1 == B6) continue;
                  if (A6 != B6 && A5 != B5 && A4 != B4 && A3 != B3 && A2 != B2 && A1 != B1)
                  {
                     int A = A6*100000+A5*10000+A4*1000+A3*100+A2*10+A1;
                     int B = B6*100000+B5*10000+B4*1000+B3*100+B2*10+B1;
                     if (MathMod(A, B) == 0)
                        Print(A6,A5,A4,A3,A2,A1,"/",B6,B5,B4,B3,B2,B1,"=",A/B);
                  }
               }
            }
         }
      }
   }
               }
            }
         }
      }
   }

Также в MQL5 чуть ускорит сравнение:

                     if (A > B && MathMod(A, B) == 0)

Но 125 ms явно не догнать.

 

А может, ввсе же в С++ ?
.
Validate- функция одного параметра.
Может по старинке... выделяем память и кэшируем bool
для всех допустимых значений аргумента?