Преобразование простых чисел

Возможный дубликат:
Помогите с проблемой алгоритма из SPOJ

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

например. конвертировать 1033 в 8179 (1033- > 1733- > 3733 → .......- > 8179)

Ответ 1

Хороший вызов для дождливого вечера в понедельник (он здесь, во всяком случае!). Это можно сделать, используя алгоритм Дейкстры. Первый шаг - создать graph, содержащий все 4-значные простые числа. Затем используйте алгоритм Дейкстры, чтобы найти кратчайший путь между начальными/конечными штрихами. Здесь реализация в Python:

#! /usr/bin/python -tt

# run as: findpath start end

import sys

(start, end) = map(int, sys.argv[1:3])

# http://primes.utm.edu/lists/small/10000.txt
f = open("10000.txt", "r")
lines = f.readlines()
f.close
lines = lines[4:-1] # remove header/footer
all = "".join(lines) # join lines
all = all.split()
all = map(int, all)

# only want the 4-digit primes
fourdigit = [p for p in all if 1000 <= p and p <= 9999]

# returns digits in a number
digits = lambda x: map(int, str(x))

# cache of digits for each prime
digits_for_nums = {}

# returns digits in a number (using cache)
def digits_for_num(x):
    global digits_for_nums
    if x not in digits_for_nums:
        digits_for_nums[x] = digits(x)
    return digits_for_nums[x]

# returns 1 if digits are same, 0 otherwise
diff = lambda pair: 1 if pair[0] == pair[1] else 0

# computes number of identical digits in two numbers
def distance(a, b):
    pair = (a, b)
    pair = map(digits_for_num, pair)
    pair = zip(pair[0], pair[1])
    pair = map(diff, pair)
    same = sum(pair)
    return same

# adjacency list representation of graph of primes
edges = {}

# construct graph
for a in fourdigit:
    edges[a] = []
    for b in fourdigit:
        if distance(a, b) == 3:
            edges[a].append(b)

infinity = sys.maxint

def smallest():
    global dist, Q
    minimum = infinity
    which = None
    for v in Q:
        if dist[v] <= minimum:
            which = v
            minimum = dist[v]
    return which

# Dijkstra algorithm
dist = {}
previous = {}
Q = edges.keys()
for v in Q:
    dist[v] = infinity
    previous[v] = None
dist[start] = 0
while len(Q) > 0:
    u = smallest()
    if dist[u] == infinity:
        break
    Q.remove(u)
    for v in edges[u]:
        alt = dist[u] + 1
        if alt < dist[v]:
            dist[v] = alt
            previous[v] = u

# get path between start/end nodes
num = end
path = [num]
while num != start:
    num = previous[num]
    path.insert(0, num)
print path

Ответ 2

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

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

Изменить: oops, только заметили, что "проверка правильности" - это шаг.

Я больше не понимаю вопроса. Сколько чисел вы должны "проверить на простоту", чтобы создать цепочку 1033 → 1733 → 3733? Если я использую сито, чтобы найти все простые числа менее 10000, сколько "шагов" имеет это?

Ответ 4

Это можно рассматривать как проблему графа. Я бы попробовал что-то в этом направлении:

  • Сгенерируйте все N-разрядные простые числа (P) без начального простого (A) и end prime (B).
  • Вычислить расстояние hamming от A до всех P, выбрать те, которые имеют расстояние 1, установить их как детей из A.
  • Повторяйте это до тех пор, пока все простые числа из P не будут помещены в график или не будет найден путь к B.
  • Возьмите кратчайший путь от A до B.