Warning: file_get_contents(/data/phpspider/zhask/data//catemap/2/python/345.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
Python 代码占用了太多的时间_Python - Fatal编程技术网

Python 代码占用了太多的时间

Python 代码占用了太多的时间,python,Python,在接受用户输入后,我编写了排列数字的代码。排序要求相邻数之和为素数。直到10作为输入代码工作正常。如果超出这个范围,系统将挂起。请让我知道优化它的步骤 ex输入8 答案应该是:(1,2,3,4,7,6,5,8) 代码如下 import itertools x = raw_input("please enter a number") range_x = range(int(x)+1) del range_x[0] result = list(itertools.permutations(rang

在接受用户输入后,我编写了排列数字的代码。排序要求相邻数之和为素数。直到10作为输入代码工作正常。如果超出这个范围,系统将挂起。请让我知道优化它的步骤

ex输入8
答案应该是:(1,2,3,4,7,6,5,8)
代码如下

import itertools

x = raw_input("please enter a number")
range_x = range(int(x)+1)
del range_x[0]
result = list(itertools.permutations(range_x))
def prime(x):
    for i in xrange(1,x,2):
        if i == 1:
            i = i+1
        if x%i==0 and i < x :
            return False
    else:
        return True

def is_prime(a):
    for i in xrange(len(a)):
        print a
        if i < len(a)-1:
            if prime(a[i]+a[i+1]):
                pass
            else:
                return False
        else:
            return True


for i in xrange(len(result)):
    if i < len(result)-1:
        if is_prime(result[i]):
            print 'result is:'
            print result[i]
            break
    else:
        print 'result is'
        print result[i-1]
导入itertools
x=原始输入(“请输入一个数字”)
range_x=range(int(x)+1)
del range_x[0]
结果=列表(itertools.排列(范围x))
def基本(x):
对于x范围内的i(1,x,2):
如果i==1:
i=i+1
如果x%i==0且i
动态规划,拯救:

def is_prime(n):
    return all(n % i != 0 for i in range(2, n))

def order(numbers, current=[]):
    if not numbers:
        return current

    for i, n in enumerate(numbers):
        if current and not is_prime(n + current[-1]):
            continue

        result = order(numbers[:i] + numbers[i + 1:], current + [n])

        if result:
            return result

    return False

result = order(range(500))

for i in range(len(result) - 1):
    assert is_prime(result[i] + result[i + 1])

您可以通过增加最大递归深度来强制它在更大的列表中工作。

以下是我对解决方案的看法。正如蒂姆·彼得斯指出的,这是一个哈密顿路径问题。 因此,第一步是以某种形式生成图形

这是生成素数的第0步。我要用筛子,但不管什么基本测试都可以。我们需要素数高达
2*n
,因为这是任意两个数字之和的最大值

m = 8
n = m + 1 # Just so I don't have to worry about zero indexes and random +/- 1's
primelen = 2 * m
prime = [True] * primelen
prime[0] = prime[1] = False
for i in range(4, primelen, 2):
    prime[i] = False
for i in range(3, primelen, 2):
    if not prime[i]:
        continue
    for j in range(i * i, primelen, i):
        prime[j] = False
好的,现在我们可以用
prime[i]
测试素性。现在它很容易使图形的边缘。如果我有一个数字I,接下来会出现什么数字。我还将利用I和j具有相反的奇偶性这一事实

pairs = [set(j for j in range(i%2+1, n, 2) if prime[i+j])
         for i in range(n)]
所以这里,
pairs[i]
是一个集合对象,它的元素是整数j,使得
i+j
是素数

现在我们需要沿着图表走。这确实是耗时的部分,所有进一步的优化都将在这里完成

chains = [
    ([], set(range(1, n))
]
将在我们行走时跟踪有效路径。元组中的第一个元素将是结果。第二个元素是所有未使用的编号或未访问的节点。这个想法是从队列中取出一条链,沿着路径走一步,然后把它放回去

while chains:
    chain, unused = chains.pop()

    if not chain:
        # we haven't even started, all unused are valid
        valid_next = unused
    else:
        # We need numbers that are both unused and paired with the last node
        # Using sets makes this easy
        valid_next = unused & pairs[chains[-1]]

    for num in valid_next:
        # Take a step to the new node and add the new path back to chains
        # Reminder, its important not to mutate anything here, always make new objs
        newchain  = chain + [num]
        newunused = unused - set([num])
        chains.append( (newchain, newunused) )

        # are we done?
        if not newunused:
            print newchain
            chains = False
请注意,如果没有有效的下一步,将删除该路径而不进行替换

这确实是内存效率低下,但运行时间合理。最大的性能瓶颈是遍历图表,因此下一个优化将是在智能位置弹出并插入路径,以对最可能的路径进行优先级排序。在这种情况下,为链使用
collections.deque
或其他容器可能会有所帮助

编辑

下面是一个如何实现路径优先级的示例。我们将为每个路径分配一个分数,并按此分数对
列表进行排序。举一个简单的例子,我建议包含“更难使用”节点的路径更有价值。也就是说,对于路径上的每一步,分数将增加
n-len(valid\u next)
修改后的代码将如下所示

import bisect
chains = ...
chains_score = [0]
while chains:
     chain, unused = chains.pop()
     score = chains_score.pop()
     ...

     for num in valid_next:
          newchain = chain + [num]
          newunused = unused - set([num])
          newscore = score + n - len(valid_next)
          index = bisect.bisect(chains_score, newscore)
          chains.insert(index, (newchain, newunused))
          chains_score.insert(index, newscore)
请记住,插入是
O(n)
,因此添加此项的开销可能相当大。对分数算法进行一些分析以保持队列长度
len(chains)
可管理是值得的。

这个答案是基于

有许多可能的解决办法。为了避免中间解决方案的过度内存消耗,可以生成随机路径。它还允许轻松利用多个cpu(每个cpu并行生成自己的路径)

在哪里:

以及:

例子 输出 输出为满足以下条件的随机序列:

  • 它是范围为1到20(包括)的排列
  • 相邻数之和为素数
时间性能 获得
n=900
的结果平均需要10秒左右,将时间外推为指数函数,得到
n=1000
的结果应该需要20秒左右:

图像是使用以下代码生成的:

import numpy as np
figname = 'hamiltonian_random_noset-noseq-900-900'
Ns, Ts = np.loadtxt(figname+'.xy', unpack=True)

# use polyfit to fit the data
# y = c*a**n
# log y = log (c * a ** n)
# log Ts = log c + Ns * log a
coeffs = np.polyfit(Ns, np.log2(Ts), deg=1)
poly = np.poly1d(coeffs, variable='Ns')

# use curve_fit to fit the data
from scipy.optimize import curve_fit
def func(x, a, c):
    return c*a**x
popt, pcov = curve_fit(func, Ns, Ts)
aa, cc = popt
a, c = 2**coeffs

# plot it
import matplotlib.pyplot as plt
plt.figure()
plt.plot(Ns, np.log2(Ts), 'ko', label='time measurements')
plt.plot(Ns, np.polyval(poly, Ns), 'r-',
         label=r'$time = %.2g\times %.4g^N$' % (c, a))
plt.plot(Ns, np.log2(func(Ns, *popt)), 'b-',
         label=r'$time = %.2g\times %.4g^N$' % (cc, aa))
plt.xlabel('N')
plt.ylabel('log2(time in seconds)')
plt.legend(loc='upper left')
plt.show()
拟合值:

>>> c*a**np.array([900, 1000])
array([ 11.37200806,  21.56029156])
>>> func([900, 1000], *popt)
array([ 14.1521409 ,  22.62916398])
为子孙后代;-),这里还有一个是基于找到哈密顿路径的。这是Python3代码。如前所述,它在找到第一条路径时停止,但可以很容易地更改以生成所有路径。在我的框中,它找到了1到900中所有
n
的解决方案,总共大约一分钟。对于略大于900的
n
,它超过了最大递归深度

prime生成器(
psieve()
)对于这个特定问题来说是一个非常复杂的工具,但我手头有它,不想再写一个;-)

路径查找器(
ham()
)是一种递归回溯搜索,通常(但不总是)使用一种非常有效的排序启发式方法:在迄今为止与路径中最后一个顶点相邻的所有顶点中,首先查看剩余出口最少的顶点。例如,这是用于解决骑士巡演问题的“常用”启发式方法。在这种情况下,它通常会找到一个完全不需要回溯的旅行。你的问题似乎比那更棘手

def psieve():
    import itertools
    yield from (2, 3, 5, 7)
    D = {}
    ps = psieve()
    next(ps)
    p = next(ps)
    assert p == 3
    psq = p*p
    for i in itertools.count(9, 2):
        if i in D:      # composite
            step = D.pop(i)
        elif i < psq:   # prime
            yield i
            continue
        else:           # composite, = p*p
            assert i == psq
            step = 2*p
            p = next(ps)
            psq = p*p
        i += step
        while i in D:
            i += step
        D[i] = step

def build_graph(n):
    primes = set()
    for p in psieve():
        if p > 2*n:
            break
        else:
            primes.add(p)

    np1 = n+1
    adj = [set() for i in range(np1)]
    for i in range(1, np1):
        for j in range(i+1, np1):
            if i+j in primes:
                adj[i].add(j)
                adj[j].add(i)
    return set(range(1, np1)), adj

def ham(nodes, adj):
    class EarlyExit(Exception):
        pass

    def inner(index):
        if index == n:
            raise EarlyExit
        avail = adj[result[index-1]] if index else nodes
        for i in sorted(avail, key=lambda j: len(adj[j])):
            # Remove vertex i from the graph.  If this isolates
            # more than 1 vertex, no path is possible.
            result[index] = i
            nodes.remove(i)
            nisolated = 0
            for j in adj[i]:
                adj[j].remove(i)
                if not adj[j]:
                    nisolated += 1
                    if nisolated > 1:
                        break
            if nisolated < 2:
                inner(index + 1)
            nodes.add(i)
            for j in adj[i]:
                adj[j].add(i)

    n = len(nodes)
    result = [None] * n
    try:
        inner(0)
    except EarlyExit:
        return result

def solve(n):
    nodes, adj = build_graph(n)
    return ham(nodes, adj)
def psieve():
进口itertools
(2,3,5,7)的收益率
D={}
ps=psieve()
下一页(ps)
p=下一个(ps)
断言p==3
psq=p*p
对于itertools中的i.count(9,2):
如果我在D:#复合
步骤=D.pop(i)
elif i$ python order-adjacent-prime-sum.py 20
[19, 18, 13, 10, 1, 4, 9, 14, 5, 6, 17, 2, 15, 16, 7, 12, 11, 8, 3, 20]
import numpy as np
figname = 'hamiltonian_random_noset-noseq-900-900'
Ns, Ts = np.loadtxt(figname+'.xy', unpack=True)

# use polyfit to fit the data
# y = c*a**n
# log y = log (c * a ** n)
# log Ts = log c + Ns * log a
coeffs = np.polyfit(Ns, np.log2(Ts), deg=1)
poly = np.poly1d(coeffs, variable='Ns')

# use curve_fit to fit the data
from scipy.optimize import curve_fit
def func(x, a, c):
    return c*a**x
popt, pcov = curve_fit(func, Ns, Ts)
aa, cc = popt
a, c = 2**coeffs

# plot it
import matplotlib.pyplot as plt
plt.figure()
plt.plot(Ns, np.log2(Ts), 'ko', label='time measurements')
plt.plot(Ns, np.polyval(poly, Ns), 'r-',
         label=r'$time = %.2g\times %.4g^N$' % (c, a))
plt.plot(Ns, np.log2(func(Ns, *popt)), 'b-',
         label=r'$time = %.2g\times %.4g^N$' % (cc, aa))
plt.xlabel('N')
plt.ylabel('log2(time in seconds)')
plt.legend(loc='upper left')
plt.show()
>>> c*a**np.array([900, 1000])
array([ 11.37200806,  21.56029156])
>>> func([900, 1000], *popt)
array([ 14.1521409 ,  22.62916398])
def psieve():
    import itertools
    yield from (2, 3, 5, 7)
    D = {}
    ps = psieve()
    next(ps)
    p = next(ps)
    assert p == 3
    psq = p*p
    for i in itertools.count(9, 2):
        if i in D:      # composite
            step = D.pop(i)
        elif i < psq:   # prime
            yield i
            continue
        else:           # composite, = p*p
            assert i == psq
            step = 2*p
            p = next(ps)
            psq = p*p
        i += step
        while i in D:
            i += step
        D[i] = step

def build_graph(n):
    primes = set()
    for p in psieve():
        if p > 2*n:
            break
        else:
            primes.add(p)

    np1 = n+1
    adj = [set() for i in range(np1)]
    for i in range(1, np1):
        for j in range(i+1, np1):
            if i+j in primes:
                adj[i].add(j)
                adj[j].add(i)
    return set(range(1, np1)), adj

def ham(nodes, adj):
    class EarlyExit(Exception):
        pass

    def inner(index):
        if index == n:
            raise EarlyExit
        avail = adj[result[index-1]] if index else nodes
        for i in sorted(avail, key=lambda j: len(adj[j])):
            # Remove vertex i from the graph.  If this isolates
            # more than 1 vertex, no path is possible.
            result[index] = i
            nodes.remove(i)
            nisolated = 0
            for j in adj[i]:
                adj[j].remove(i)
                if not adj[j]:
                    nisolated += 1
                    if nisolated > 1:
                        break
            if nisolated < 2:
                inner(index + 1)
            nodes.add(i)
            for j in adj[i]:
                adj[j].add(i)

    n = len(nodes)
    result = [None] * n
    try:
        inner(0)
    except EarlyExit:
        return result

def solve(n):
    nodes, adj = build_graph(n)
    return ham(nodes, adj)