通过大多数经济努力实现合理结果的算法

时间:2018-04-10 07:54:59

标签: python algorithm design-patterns

假设阅读书籍时有六种问题需要处理,
我将详细说明如下:

while True:
    if encounter A :
        handle A
    #during handling the problem, it might spawn new problems of
    #A, B, C, D, E,
        produce  (A,B..E or null)
        continue

    if B occurs:
        handle B
    #during hanlding the problem, it might spwan new problems
    #A, B, C, D, E,
        produce  (A,B..E or null)
        continue

    if C happens:
        handle C
        produce (A,B..E or null)
        continue
    ...

    if there are no problmes:
        break

假设我有3个问题,
上面的程序可能会在第一个程序上无限循环而从不接触第二个程序。

举一个例子,我正在读一本书,
'问题A'被定义为遇到'新词',处理它是查找词典 抬头的时候,我可能会再来一个新词,另一个词和另一个词 在这种情况下,我永远不会读完一本书的一句话。

作为解决方案,
我介绍了一个容器来收集问题,对它们进行值加权然后确定执行哪一个。

def solve_problems(problems)
    problem_backet = list(problems)
    while True:
        if problem_backet not is null:
            #value-weighted all the problem 
            #and determine one to implement
            value_weight problems
            problem = x

        if problem == A:
            handle A
            problem_backet.append(new_problem)
            continue

        if problem == B:
            handle B
            problem_backet.append(new_problem)
            continue
        ...
        if problem_backet is null:
            return 

我试着寻求灵感并提高效率。

def solve_problems(problems):
    global problem_backet
    problem_backet = list(problems)
    value_weight problems
    problem = x
    if problem == A:
        handle A
        problem_backet.append(new_problem)
        solve_problems(problem_backet)
    if problem == B:
        handle B
        problem_backet.append(new_problem)
        solve_problems(problem_backet)
    if problem == C:
        handle C
        problem_backet.append(new_problem)
        solve_problems(problem_backet)
    ...
    if problem_backet is null:
        return

同样,value_weighted进程耗费巨大的努力和时间。

如何在正确的算法中解决这样的问题?

3 个答案:

答案 0 :(得分:1)

你可以做几件事来解决这个问题。

其中之一是在机器学习风格中设置“max-iterations”或“max-effort”的值,您可以投资于阅读书籍。因此,您将仅执行(处理)多个操作,直到达到限制。此解决方案将如下所示:

while(effortRemaining > 0){
     # Do your actions
}

根据您需要定义的某个指标,您所执行的操作应该是报告更多优势/更少工作量的操作。

当您执行某个操作(句柄)时,您会从effortRemaining中减去该操作的成本/工作量,然后继续您的流程。

答案 1 :(得分:1)

  

'问题A'定义为遇到一个新单词',处理它是查找字典。   抬头时,我可能会遇到另一个新词,另一个词。   在这种情况下,我永远不会读完一本书中的一句话。

看起来它最终会最终读取句子,因为新单词的数量受字典大小的限制。一般来说,这对我来说听起来不错,除非有其他一些未明确提及的限制,比如在有限的时间内完成句子阅读。

  

如何在正确的算法中解决这样的问题?

好吧,如果没有"有限的时间"限制,你原来的算法几乎是完美的。为了使整体性能更好,我们可能首先处理所有问题A,然后转移到B,依此类推。它将增加我们算法的数据局部性和整体性能。

但是如果有一个有限的时间"限制,我们最终可以阅读完整的句子(没有完全理解)或最终阅读部分句子(完全理解那部分)或介于两者之间(如@Lauro Bravar建议)。

从上面的示例中我们不清楚我们如何处理value_weight,但这类问题的正确名称是优先级排队。有各种算法和实现,请查看维基百科页面了解详细信息:https://en.wikipedia.org/wiki/Priority_queue

答案 2 :(得分:0)

你已经有了算法(在Andriy的帮助下获得了优先级队列),但你缺乏设计。当我看到你的多个if检查问题的类型时,我认为是多态的。 为什么不尝试OOP?您有两个要定义的对象:问题和优先级队列。幸运的是,优先级队列在heapq模块中定义。让我们关注这个问题: 在其核心定义中,它被处理并可能与其他问题进行比较(这或多或少是紧急的)。请注意,在OOP原则的指导下,我没有谈到问题的结构或实现, 但只有问题的功能

class Problem()
    def handle(self, some args): # we may need a dictionary, a database connection, ...
        ...

    def compare(self, other):
        ...

但是你说当处理问题时,它可能会给队列增加新的问题。因此,让我们为handle的定义添加精度:

def handle(self, queue, some args): # we still may need a dictionary, a database connection, ...
    ...

在Python中,compare是名为__lt__的{​​{3}},其中"低于"。 (你有其他特殊的比较方法,但__lt__就足够了。)

这是一个基本的实现示例:

class Problem():
    def __init__(self, name, weight):
        self.__name = name
        self.__weight = weight

    def handle(self, queue):
        print ("handle the problem {}".format(self))
        while random.random() > 0.75: # randomly add new problems for the example
            new_problem = Problem(name*2, random.randint(0, 100))
            print ("-> Add the problem {} to the queue".format(new_problem))
            heapq.heappush(queue, new_problem) # add the problem to the queue

    def __lt__(self, other):
         return self.__weight > other.__weight # note the >

    def __repr__(self): # to show in lists
        return "Problem({}, {})".format(self.__name, self.__weight)

等待!为什么"低于"和>?这是因为模块heapq是最小堆:它首先返回最小元素。因此,我们将大权重定义为小于权重。

现在,我们可以为示例构建一个包含伪数据的开始队列:

queue = []
for name in ["foo", "bar", "baz"]:
    problem = Problem(name, random.randint(0, 100))
    heapq.heappush(queue, problem) # add the problem to the queue

运行主循环:

while queue:
    print ("Current queue", queue)
    problem = heapq.heappop(queue) # the problem with the max weight in O(lg n)
    problem.handle(queue)

我想你能够继承Problem类来表示你可能想要处理的各种问题。