如何优化python动态编程背包(多处理?)

如何优化python动态编程背包(多处理?),python,knapsack-problem,pypy,Python,Knapsack Problem,Pypy,我已经解决了,但它仍然太慢,无法被接受 我也尝试过让它使用多处理,但我失败了,因为它仍然比较慢。 即使使用pypy,基本实现也会在spoj上返回“超出时间限制”。 那么,我该如何改进它呢 多处理实现有什么问题 # -- shipyard from collections import defaultdict #W = 100 total weight #N = 2 number of types #value | weight #1 1 #30 50 # resu

我已经解决了,但它仍然太慢,无法被接受

我也尝试过让它使用多处理,但我失败了,因为它仍然比较慢。 即使使用
pypy
,基本实现也会在spoj上返回“超出时间限制”。 那么,我该如何改进它呢

多处理实现有什么问题

#  -- shipyard
from collections import defaultdict
#W = 100  total weight
#N = 2    number of types
#value | weight
#1       1
#30      50
# result -> 60 = minimum total value
#c = [1, 30]
#w = [1, 50]

def knap(W, N, c, w):

   f    = defaultdict(int)
   g    = defaultdict(bool)
   g[0] = True
   for i in xrange(N):
      for j in xrange(W):
         if g[j]:
            g[j+w[i]] = True
            #print "g("+str(j+w[i])+") = true"
            if ( f[j+w[i]]==0 or f[j+w[i]]>f[j]+c[i]):
               f[j+w[i]] = f[j]+c[i]
               #print " f("+str(j+w[i])+") = ",f[j+w[i]]

   if g[W]:
      print f[W]
   else:
      print -1

def start():
   while True:
      num_test = int(raw_input())

      for i in range(num_test):
         totWeight = int(raw_input())
         types    = int(raw_input())
         costs    = defaultdict(int)
         weights  = defaultdict(int)
         for t in range(int( types )):
             costs[t], weights[t] = [int(i) for i in raw_input().split()]

         knap(totWeight, types, costs, weights)
      return

if __name__ == '__main__': 
    start()
这是多处理版本:

#  -- shipyard
from multiprocessing import Process, Queue
from collections import defaultdict
from itertools import chain   

W  = 0
c  = {} #[]
w  = {} #[]

def knap(i, g, f, W, w, c, qG, qF):

   for j in xrange( W ):
      if g[j]:
         g[j+w[i]] = True
         #print "g("+str(j+w[i])+") = true"
         if ( f[j+w[i]]==0 or f[j+w[i]]>f[j]+c[i]):
            f[j+w[i]] = f[j]+c[i]
            #print " f("+str(j+w[i])+") = ",f[j+w[i]]
   qG.put( g)
   qF.put( f)

def start():
   global f, g, c, w, W

   while True:
      num_test = int(raw_input())

      for _ in range(num_test):
         qG = Queue()
         qF = Queue()
         W  = int(raw_input())
         N  = int(raw_input()) # types
         c  = {} #[0 for i in range(N)]
         w  = {} #[0 for i in range(N)]
         f  = defaultdict(int)
         g  = defaultdict(bool)
         g[0] = True

         for t in range( N ):
             c[t], w[t] = [int(i) for i in raw_input().split()]

         # let's go parallel
         for i in xrange(0, N, 2):
            k1 = Process(target=knap, args=(i,   g, f, W, w, c, qG, qF))
            k2 = Process(target=knap, args=(i+1, g, f, W, w, c, qG, qF))
            k1.start()
            k2.start()
            k1.join()
            k2.join()
            #while k1.is_alive(): # or k2.is_alive():
            #   None
            #g2 = defaultdict(bool, chain( g.iteritems(), qG.get().iteritems(), qG.get().iteritems()))
            #f2 = defaultdict(int,  chain( f.iteritems(), qF.get().iteritems(), qF.get().iteritems()))
            g2 = defaultdict(bool, g.items()+ qG.get().items()+ qG.get().items())
            f2 = defaultdict(int,  f.items()+ qF.get().items()+ qF.get().items())

            g = g2
            f = f2

            print "\n g: ", len(g), "\n f: ", len(f),"\n"

         if g[W]:
            print f[W]
         else:
            print -1   


      return

if __name__ == '__main__': 
    start()

我可能还不知道如何使两个进程在同一个字典上高效地工作

许多使用Python的人在编程竞赛网站上面临同样的问题。我发现,对于那些需要在大数据结构上构造和迭代的接受大输入的问题,最好是完全抛弃Python。在C或C++中简单地重新实现相同的解决方案。众所周知,Python的速度比经过优化的C/C++代码慢10到100倍


您的代码看起来不错,但要获得更快的速度,您所能做的实在太少了(除了大的O改进或经历诸如多处理之类的困难)。如果必须使用Python,请尽量避免创建不必要的大列表,并使用您能想到的最有效的算法。在提交解决方案之前,您还可以尝试生成并运行大型测试用例。

一些编程竞赛将明确禁止多线程或阻止多线程,因此请尝试到其他地方查看。在那些时候,我的方法是使用分析工具来查看代码在哪里挣扎。您可以尝试内置的cProfile(
python-mcprofile-o
),然后使用这个出色的可视化工具:
一旦你有了你的视觉化环顾四周,就去挖掘盒子。有些时候,有些事情不是直接显而易见的,但一旦检查了运行时间就有意义了。i、 一个常见的问题(不确定是否是您的情况)是检查列表成员资格。在这种情况下,使用集合要快得多,如果您以后需要订单,通常需要保留一个单独的列表和集合。关于将变量导入局部空间等,还有很多提示。您可以在此处查看列表:

这肯定是最佳选项,但并不总是一个选项。总有一个中间步骤,您可以将程序的某些部分编码为C/C++扩展模块。请看这里:如果速度在某些方面是我关心的问题,我肯定会在商业项目中实现C扩展模块,但这对于一个竞赛问题来说确实是值得的?你必须使用
defaultdict
?由于列表的范围是预先知道的,因此最好使用
[None]*int(types)
初始化数组。