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

简介: 问题给定 n 个作业,每一个作业都有两项子任务需要分别在两台机器上完成。每一个作业必须先由机器1 处理,然后由机器2处理。试设计一个算法找出完成这n个任务的最佳调度,使其机器2完成各作业时间之和达到最小。

问题

给定 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

img_46467092c87716f7d79be05249884db1.jpg

解编码:(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

效果图

img_1218c6f7269c8cb9a8b26f7ebbfabf51.jpg

目录
相关文章
|
Python
python 回溯法 记录
一直不是太理解回溯法,这几天集中学习了一下,记录如下。 回溯法有“通用的解题法”之称。 1.定义:  也叫试探法,它是一种系统地搜索问题的解的方法。 2.基本思想:  从一条路往前走,能进则进,不能进则退回来,换一条路再试。
3173 0
|
3月前
|
数据采集 机器学习/深度学习 人工智能
Python:现代编程的首选语言
Python:现代编程的首选语言
287 102
|
3月前
|
数据采集 机器学习/深度学习 算法框架/工具
Python:现代编程的瑞士军刀
Python:现代编程的瑞士军刀
314 104
|
3月前
|
人工智能 自然语言处理 算法框架/工具
Python:现代编程的首选语言
Python:现代编程的首选语言
260 103
|
3月前
|
机器学习/深度学习 人工智能 数据挖掘
Python:现代编程的首选语言
Python:现代编程的首选语言
193 82
|
2月前
|
Python
Python编程:运算符详解
本文全面详解Python各类运算符,涵盖算术、比较、逻辑、赋值、位、身份、成员运算符及优先级规则,结合实例代码与运行结果,助你深入掌握Python运算符的使用方法与应用场景。
179 3
|
2月前
|
数据处理 Python
Python编程:类型转换与输入输出
本教程介绍Python中输入输出与类型转换的基础知识,涵盖input()和print()的使用,int()、float()等类型转换方法,并通过综合示例演示数据处理、错误处理及格式化输出,助你掌握核心编程技能。
420 3
|
2月前
|
并行计算 安全 计算机视觉
Python多进程编程:用multiprocessing突破GIL限制
Python中GIL限制多线程性能,尤其在CPU密集型任务中。`multiprocessing`模块通过创建独立进程,绕过GIL,实现真正的并行计算。它支持进程池、队列、管道、共享内存和同步机制,适用于科学计算、图像处理等场景。相比多线程,多进程更适合利用多核优势,虽有较高内存开销,但能显著提升性能。合理使用进程池与通信机制,可最大化效率。
264 3
|
2月前
|
Java 调度 数据库
Python threading模块:多线程编程的实战指南
本文深入讲解Python多线程编程,涵盖threading模块的核心用法:线程创建、生命周期、同步机制(锁、信号量、条件变量)、线程通信(队列)、守护线程与线程池应用。结合实战案例,如多线程下载器,帮助开发者提升程序并发性能,适用于I/O密集型任务处理。
260 0