以最短的执行时间重新安排任务

时间:2017-01-08 00:24:03

标签: python algorithm python-2.7 optimization

在下面的任务中重新安排问题,在Python 2.7中发布问题和我的代码。我的具体问题,

  1. 优化算法时间复杂度(或空间复杂度)的任何更好的想法?
  2. 当我们发现无法安排任务时(意味着由另一个不同的任务分开,因此没有额外的等待时间),我当前的实现是将这些任务放在任何空闲的插槽中(参考while counter < f的循环) ,我想知道我应该做的是(1)将剩余的未安排的任务/频率放回堆中,以及(2)找到要处理的下一个高频任务?
  3. 对于公告第2点,我测试了我的代码是否正常(ok表示我的代码返回最少的执行时间加上等待时间),但如果有任何错误,我应该做(1)和(2)除了我当前的实现,请随时指出。

    问题

    给定一组任务,如[A,A,B]和int k,这是两个相同任务之间的等待时间。如果允许重新排列任务,请计算最小总执行时间。假设每个单独任务的执行是1。

    在上面的例子中 A A B,k = 1,没有重新排列,执行时间为4:

    A wait A B
    
    1  1   1 1
    

    重新排列,执行时间为3:

    A B A
    
    1 1 1
    

    源代码

    from collections import defaultdict
    import heapq
    
    
    def rearrange_tasks(tasks):
        freq = defaultdict(int)
        for t in tasks:
            freq[t] += 1
        h = []
        heapq.heapify(h)
        result = [0] * len(tasks)
        for t,f in freq.items():
            heapq.heappush(h, (-f, t))
        while len(h) > 0:
            f, t = heapq.heappop(h)
            f = -f
            write_index = 0
            while write_index < len(result) and result[write_index] != 0:
                write_index += 1
            counter = 0
            while write_index < len(result) and counter < f:
                result[write_index] = t
                write_index += 2
                counter += 1
            # write tasks which have to be consecutive
            write_index = 0
            while counter < f:
                if result[write_index] != 0:
                    write_index += 1
                else:
                    result[write_index] = t
                    write_index += 1
                    counter += 1
        return result
    
    
    def calculate_execution_time(tasks, k):
        exec_time = 0
        for i, t in enumerate(tasks):
            if i == 0:
                exec_time += 1
                continue
            if t == tasks[i-1]:
                exec_time += k
                exec_time += 1
            else:
                exec_time += 1
        return exec_time
    
    if __name__ == "__main__":
        tasks = ['A', 'A', 'B']
        result = rearrange_tasks(tasks)
        print result
        print calculate_execution_time(result, 1)
    
        tasks = ['A', 'A', 'A', 'A', 'C', 'D', 'E', 'E', 'B', 'B', 'B']
        result = rearrange_tasks(tasks)
        print result
        print calculate_execution_time(result, 1)
    

    修改1

    使用条件while write_index < len(result) and counter < f:(条件counter < f:

    除外)修复索引错误

1 个答案:

答案 0 :(得分:1)

看起来您的代码会在某些输入上引发错误。例如,我试过这个:

['A', 'A', 'B', 'C', 'C', 'C', 'C', 'C', 'C', 'C', 'C']

...
  File "orig.py", line 22, in rearrange_tasks
    result[write_index] = t
IndexError: list assignment index out of range

以下是一些建议的更改。他们更少关注优化速度,更多关注算法清晰度。我有点怀疑你应该过多担心速度 - 你的输入有多大以及有多少不同的任务值?该算法似乎主要是线性的,特别是如果不同任务值的数量很小。

from collections import Counter
from heapq import heapify, heappop, heappush

def rearrange_tasks(tasks):

    # Make a heap of (-FREQ, TASK) tuples.
    freq = Counter(tasks)
    h = [(-f, t) for t, f in freq.items()]
    heapify(h)

    result = []
    prev = None
    while h:
        # Get the most frequent item.
        f, t = heappop(h)

        # If it is a repeat and if there are other items,
        # put it back and grab 2nd most frequent item instead.
        if t == prev and h:
            item = (f, t)
            f, t = heappop(h)
            heappush(h, item)

        # Put selected item back on heap, after adjusting frequency.
        if f < -1:
            heappush(h, ((f + 1), t))

        # Add task to the result.
        result.append(t)
        prev = t

    return result

def calculate_execution_time(tasks, k):
    n = 0
    prev = None
    for t in tasks:
        n += 1 + int(t == prev) * k
        prev = t
    return n

def run(tasks):
    result = rearrange_tasks(tasks)
    assert Counter(tasks) == Counter(result)
    print
    print 'len    =', len(tasks)
    print 'time   =', calculate_execution_time(result, 1)
    print 'result =', ''.join(result)

if __name__ == "__main__":
    run('AAB')
    run('AABCCCCCCCC')
    run('AAAACDEEBBB')
    run('AAAACDEEBBBBBBBBBBBB')