• python 回溯法 子集树模板 系列 —— 13、最佳作业调度问题


    问题

    给定 n 个作业,每一个作业都有两项子任务需要分别在两台机器上完成。每一个作业必须先由机器1 处理,然后由机器2处理。

    试设计一个算法找出完成这n个任务的最佳调度,使其机器2完成各作业时间之和达到最小。

    分析:

    看一个具体的例子:

    tji 机器1 机器2
    作业1 2 1
    作业2 3 1
    作业3 2 3

    最优调度顺序:1 3 2
    处理时间:18

    这3个作业的6种可能的调度方案是1,2,3;1,3,2;2,1,3;2,3,1;3,1,2;3,2,1;

    它们所相应的完成时间和分别是19,18,20,21,19,19。易见,最佳调度方案是1,3,2,其完成时间和为18。

    以1,2,3为例:

    作业1在机器1上完成的时间为2,在机器2上完成的时间为3
    作业2在机器1上完成的时间为5,在机器2上完成的时间为6
    作业3在机器1上完成的时间为7,在机器2上完成的时间为10
    3+6+10 = 19

    1,3,2

    作业1在机器1上完成的时间为2, 在机器2上完成的时间为3
    作业3在机器1上完成的时间为4,在机器2上完成的时间为7
    作业2在机器1上完成的时间为7,在机器2上完成的时间为8
    3+7+8 = 18

    解编码:(X1,X2,...,Xn),Xi表示顺序i执行的任务编号。所以,一个解就是任务编号的一个排列。

    解空间:{(X1,X2,...,Xn)| Xi属于S,i=1,2,...,n},S={1,2,...,n}。所以,解空间就是任务编号的全排列。

    讲道理,要套用回溯法的全排列模板。

    不过,有了前面两个例子做铺垫,这里套用回溯法的子集树模板。

    代码

    '''
    最佳作业调度问题 
    
    tji          机器1     机器2
    作业1         2          1
    作业2         3          1
    作业3         2          3
    
    '''
    
    n = 3 # 作业数
    # n个作业分别在两台机器需要的时间
    t = [[2,1],
         [3,1],
         [2,3]]
         
    x = [0]*n   # 一个解(n元数组,xi∈J)
    X = []      # 一组解
    
    best_x = [] # 最佳解(一个调度)
    best_t = 0  # 机器2最小时间和
    
        
    # 冲突检测
    def conflict(k):
        global n, x, X, t, best_t
        
        # 部分解内的作业编号x[k]不能超过1
        if  x[:k+1].count(x[k]) > 1:
            return True
            
        # 部分解的机器2执行各作业完成时间之和未有超过 best_t
        #total_t = sum([sum([y[0] for y in t][:i+1]) + t[i][1] for i in range(k+1)])
        j2_t = []
        s = 0
        for i in range(k+1):
            s += t[x[i]][0]
            j2_t.append(s + t[x[i]][1])
        total_t = sum(j2_t)
        if total_t > best_t > 0:
            return True
        
        return False # 无冲突
    
        
    # 最佳作业调度问题 
    def dispatch(k): # 到达第k个元素
        global n, x, X, t, best_t, best_x
        
        if k == n:  # 超出最尾的元素
            #print(x)
            #X.append(x[:]) # 保存(一个解)
            
            # 根据解x计算机器2执行各作业完成时间之和
            j2_t = []
            s = 0
            for i in range(n):
                s += t[x[i]][0]
                j2_t.append(s + t[x[i]][1])
            total_t = sum(j2_t)
            if best_t == 0 or total_t < best_t:
                best_t = total_t
                best_x = x[:]
        else:
            for i in range(n): # 遍历第k个元素的状态空间,机器编号0~n-1,其它的事情交给剪枝函数
                x[k] = i
                if not conflict(k): # 剪枝
                    dispatch(k+1)
    
    
    
    # 测试
    dispatch(0)
    print(best_x) # [0, 2, 1]
    print(best_t) # 18
    
    

    效果图

  • 相关阅读:
    无法设置 / 添加网络打印机?报错 无法保持设置?
    tp剩余未验证内容-5
    再谈 iptables 防火墙的 指令配置
    tp剩余未验证内容-4
    tp剩余未验证内容-3
    CentOS7.4安装配置mysql8 TAR免安装版
    CentOS7中systemctl的使用与CentOS6中service的区别
    CentOS下如何查看并杀死僵尸进程
    CentOS SVN服务器管理多项目
    swoole+Redis实现实时数据推送
  • 原文地址:https://www.cnblogs.com/hhh5460/p/6935216.html
Copyright © 2020-2023  润新知