转换素数

时间:2010-09-06 18:13:23

标签: algorithm primes

  

可能重复:
  Help with algorithm problem from SPOJ

遇到了这个面试问题。给定两个n位素数,将第一个素数转换为第二个一次改变一个数字。中间数字也需要是素数。这需要以最少的步骤完成(检查素数和更改数字被认为是步骤)

E.g。将1033转换为8179(1033-> 1733-> 3733-> .......-> 8179)

4 个答案:

答案 0 :(得分:4)

周一晚上下雨的好挑战(无论如何都在这里!)。这可以使用Dijkstra's algorithm完成。第一步是创建一个包含所有4位数素数的graph。然后使用Dijkstra算法找到开始/结束素数之间的最短路径。这是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's 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

答案 1 :(得分:3)

这是(最特殊情况)最短路径问题。您正在寻找两个指定顶点之间的最小路径,通过顶点为素数的图形,并且顶点通过边连接,当且仅当它们在基数10表示时恰好在一个数字上不同时。所有边都有重量1。

对于这种特殊情况的特定结构缺乏更好的想法:对于4位数,这肯定可以用你最喜欢的寻路算法在可忽略的时间内完成。

编辑:oops,只是注意到“检查素性”是一个步骤。

我不再理解这个问题。你需要多少个数字来“检查素性”才能生成链1033 - &gt; 1733 - &gt; 3733?如果我使用筛子找到小于10000的所有质数,那么采取了多少“步骤”?

答案 2 :(得分:0)

最佳方法可能是depth-first search with iterative deepening,因为请求的最小步数。初始深度将是两个数字之间不同的位数。

答案 3 :(得分:0)

这可以被认为是一个图形问题。我会尝试这些方法:

  • 生成所有N位素数(P),不包括起始素数(A)和结束素数(B)。
  • 计算从A到所有P的汉明距离,选择距离为1的距离,将它们设为A的子项。
  • 重复此操作,直到P中的所有素数都放入图表或找到B的路径。
  • 选择从A到B的最短路径。