2014-11-23 3 views
0

ГоловоломкаЧто представляет собой более эффективная реализация этой головоломки?

Для каждого входного числа п (п < 10) существует номер выходного т таким образом, что: первая цифра

  • М является п
  • м является п-значный номер
  • каждые 2-значная последовательность внутри m должно быть другим простым числом

Выход должен m, где m - наименьшее число, удовлетворяющее указанным выше условиям. Если такого номера нет, выход должен быть равен -1;

Примеры

п = 3 -> т = 311

п = 4 -> т = 4113 (заметим, что это не 4111, как будет повторять 11)

п = 9 -> т = 971131737

Мой несколько рабочий раствор

Вот мой первый удар в этом, подход «грубой силы». Я ищу более элегантное решение, так как это очень неэффективно, так как n растет.

public long GetM(int n) 
{ 
    long start = n * (long)Math.Pow((double)10, (double)n - 1); 
    long end = n * (long)Math.Pow((double)10, (double)n); 
    for (long x = start; x < end; x++) 
    { 
     long xCopy = x; 
     bool allDigitsPrime = true; 
     List<int> allPrimeNumbers = new List<int>(); 
     while (xCopy >= 10) 
     { 
      long lastDigitsLong = xCopy % 100; 
      int lastDigits = (int)lastDigitsLong; 
      bool lastDigitsSame = allPrimeNumbers.Count != 0 && allPrimeNumbers.Contains(lastDigits); 
      if (!IsPrime(lastDigits) || lastDigitsSame) 
      { 
       allDigitsPrime = false; 
       break; 
      } 

      xCopy /= 10; 
      allPrimeNumbers.Add(lastDigits); 
     } 

     if (n != 1 && allDigitsPrime) 
     { 
      return x; 
     } 
    } 

    return -1; 
} 

Первые мысли о том, как это можно было бы сделать более эффективным

Таким образом, очевидно, узким местом здесь прохождения через весь список номеров, которые могли бы выполнить это условие из п .... к (n + 1) ..... Вместо того, чтобы просто увеличивать количество каждой итерации цикла, должен быть некоторый умный способ пропуски чисел, основанный на требовании, чтобы 2-значные последовательности были первыми. Например, для n = 5 нет точки, проходящей через 50000 - 50999 (50 не является простым), 51200 - 51299 (12 не является простым), но я не был уверен, как это можно реализовать или если это было бы достаточно оптимизации, чтобы алгоритм выполнялся для n = 9.

Любые идеи относительно этого подхода или другого подхода к оптимизации?

+1

n = 4 -> m = 971131737, кажется неправильным. Возможно, вы имели в виду n = 9 -> m = 971131737? – sara

+1

Требование каждой двухзначной последовательности внутри m должно быть другим простым числом - ограничивает размер N до 25 (число простых чисел до 100) Поэтому - я предлагаю жестко кодировать его :) – sara

+0

да, хорошее место @ sara :) Хм, это хорошая идея, может быть, вы можете сгенерировать m, используя список простых чисел, а не наоборот. Благодаря! :) – Metro101

ответ

2

Это возможное решение, в R, с использованием рекурсии. Интересно было бы построить дерево всех возможных путей

# For every input number n (n < 10) 
# there is an output number m such that: 

# m's first digit is n 
# m is an n digit number 
# every 2 digit sequence inside m must be a different prime number 
# Need to select the smallest m that meets the criteria 

library('numbers') 

mNumHelper <- function(cn,n,pr,cm=NULL) { 
    if (cn == 1) { 
    if (n==1) { 
     return(1) 
    } 
    firstDigit <- n 
    } else { 
    firstDigit <- mod(cm,10) 
    } 
    possibleNextNumbers <- pr[floor(pr/10) == firstDigit] 
    nPossible = length(possibleNextNumbers) 
    if (nPossible == 1) { 
    nextPrime <- possibleNextNumbers 
    } else{ 
    # nextPrime <- sample(possibleNextNumbers,1) 
    nextPrime <- min(possibleNextNumbers) 
    } 
    pr <- pr[which(pr!=nextPrime)] 
    if (is.null(cm)) { 
    cm <- nextPrime 
    } else { 
    cm = cm * 10 + mod(nextPrime,10) 
    } 
    cn = cn + 1 
    if (cn < n) { 
    cm = mNumHelper(cn,n,pr,cm) 
    } 
    return(cm) 
} 

mNum <- function(n) { 
    pr<-Primes(10,100) 
    m <- mNumHelper(1,n,pr) 
} 
for (i in seq(1,9)) { 
    print(paste('i',i,'m',mNum(i))) 
} 

Пример вывода

[1] "i 1 m 1" 
[1] "i 2 m 23" 
[1] "i 3 m 311" 
[1] "i 4 m 4113" 
[1] "i 5 m 53113" 
[1] "i 6 m 611317" 
[1] "i 7 m 7113173" 
[1] "i 8 m 83113717" 
[1] "i 9 m 971131737" 

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

+0

«i 3 м 317» не выглядит корректно для меня. Вопрос уже показывает, что правильный вывод для 3 равен 311, а не 317, и, прочитав мои требования, я согласен, что правильный результат равен 311. – hvd

+0

Да, похоже, что все ответы неверны, кроме n = 2. I «Немного не уверен, что часть обратного отслеживания работает, когда вы на неправильном пути вы вызываете return (mNum (n)), как это отличается от исходного? Я подозреваю, что путь кода не попал, поскольку у меня есть итеративная реализация этого, и нет необходимости в обратном пути для n <10 :) – Metro101

+0

@hvd для n = 3, результат 317, первая цифра равна 3 , это 3-значное число, а 2-значные последовательности - 31 и 17, оба - простое. Где ошибка? Каждое число соответствует трем критериям. Причина mNum (n) отличается тем, что выборка случайна, поэтому каждый прогон может дать другой набор решений. Легкая проблема в том, что когда n равно 9, единственное простое число равно 97, поэтому ни один из других выбранных простых чисел не может закончиться в 9, так как нет второго числа, начинающегося с 9. –

3

Вам не нужно пробовать все номера. Вместо этого вы можете использовать другую стратегию, суммированную как «попытаться добавить цифру».

Какая цифра? Ну, цифра таких, что

  1. образует простой вместе с вашей текущей последней цифрой
  2. премьер формируется не произошли в числе перед

Это должно быть сделано рекурсивно (не итеративен) , потому что у вас могут закончиться варианты, а затем вам придется отступать и попробовать другую цифру ранее в номере.

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

+0

Да, это правильный подход, работал как шарм с итерационным подходом (кажется, работает для n <10). Но я все еще пытаюсь понять, как реализовать его рекурсивно. – Metro101

+0

@ Metro101 wait, он работает итеративно? Теперь это интересно, это что-то фундаментальное или просто совпадение? – harold

+0

Я думаю, что это просто совпадение, для небольших n-s он не попадает в краевой случай, когда заканчиваются простые числа, которые начинаются с определенной цифры, поэтому нет необходимости возвращаться назад. Было бы интересно узнать, до каких пор он работает. – Metro101

0

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

Смежные вопросы