回溯法 批处理作业调度_回溯法之批处理作业调度

本文介绍了如何运用回溯法解决批处理作业调度问题,通过详细解析问题描述、问题分析、代码实现,展示如何寻找使作业完成时间最小的调度方案。通过实例展示了算法的运行过程,并给出了完整的C语言代码实现。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

回溯法之批处理作业调度

1. 问题描述

​n个作业集合{1, 2, ..., n}。每个作业先由机器1处理,再由机器2处理。作业i需要机器j处理的时间为Mij 。

Mij

机器1

机器2

作业1

2

1

作业2

3

1

作业3

2

3

​对于一个确定的作业调度,设Fij 是作业i在机器j上完成的具体时间。所有作业在机器2上完成的具体时间(时刻)之和f称为该作业调度的完成时间和。

​要求:对于给定的n个作业,制定最佳作业调度方案(一个排列),使其完成时间和达到最小

2. 问题分析

​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。

​Fi1、Fi2表示事件i分别在机器1和机器2上完成的时间。

作业顺序

Fi1

Fi2

f

begin

0

0

0

2

3

3

4

7

10

7

8

18

​假设此时1-2-3的作业调度已经完成计算,遍历到了1-3-2的序列。

​首先是①,将调用f1 += M[x[j]][1];表示作业1在机器1需要2时间才能完成,接下来使用f2[i] = ((f2[i - 1] > f1) ? f2[i - 1] : f1) + M[x[j]][2];比较F02 和 F11 的大小,即需要等待前一个作业在机器2完成计算才能在机器2开始本次作业,再使用F02 和 F11的较大值F11+作业2在机器2的工作时间1得到F12为3,在使用f += f2[i],将3赋值给f。

​到③,调用f1 += M[x[j]][1];,F21变为2+2=4,再比较F12和F21,将较大的F21+3=7赋值给F22。f变为10。

​到②,F31变为7,比较F22和F31,将7+1=8复制给F32,最终将f变为18,得到最终结果。

3. 代码求解

​该问题的解空间:排列树:

​使用到的全局变量:

M 各作业所需的处理时间

x 当前作业调度

bestx 当前最优作业调度

f2 机器2完成的处理时间

f1 机器1完成的处理时间

f 完成时间和

bestf 当前最优值

n 作业数

​核心求解代码:

void BackTrack(int i) {

// i > n表示已经访问到叶子结点,即一个作业调度遍历完成

// 将此时的最优解暂时保存到bestx中

if (i > n) {

for (int j = 1; j <= n; j++) {

bestx[j] = x[j];

bestf = f;

}

} else {

// 若没找到此时的最优解,则对当前的求解树的子节点遍历求解

for (int j = i; j <= n; j++) {

// 上述的问题求解过程

f1 += M[x[j]][1];

f2[i] = ((f2[i - 1] > f1) ? f2[i - 1] : f1) + M[x[j]][2];

f += f2[i];

// 如果f小于当前的最小值,代表这个分支可以继续运算,否则直接裁去该分支,达到优化算法的目的

if (f < bestf) {

swap(i, j);

// 递归求解

BackTrack(i + 1);

// 递归运算后,需要回退到上一层排列树

swap(i, j);

}

// 本条路径求解结束后回退到原本的状态

f1 -= M[x[j]][1];

f -= f2[i];

}

}

}

4. 完整代码

/**

* 回溯法求解批处理作业调度问题

*

* 主要由BackTrack函数递归调用求解问题

* 使用bsetf保存最优解,bestx保存最优的作业调度序列

**/

#include

#include

#define MAXROW 4

#define MAXCOL 3

/**

* M 各作业所需的处理时间

* x 当前作业调度

* bestx 当前最优作业调度

* f2 机器2完成的处理时间

* f1 机器1完成的处理时间

* f 完成时间和

* bestf 当前最优值

* n 作业数

**/

int M[MAXROW][MAXCOL], x[MAXROW], bestx[MAXROW], f2[MAXROW], f1, f, bestf, n;

// 值交换函数

void swap(int i, int j) {

int tmp = x[i];

x[i] = x[j];

x[j] = tmp;

}

void BackTrack(int i) {

// i > n表示已经访问到叶子结点,即一个作业调度遍历完成

// 将此时的最优解暂时保存到bestx中

if (i > n) {

for (int j = 1; j <= n; j++) {

bestx[j] = x[j];

bestf = f;

}

} else {

// 若没找到此时的最优解,则对当前的求解树的子节点遍历求解

for (int j = i; j <= n; j++) {

f1 += M[x[j]][1];

f2[i] = ((f2[i - 1] > f1) ? f2[i - 1] : f1) + M[x[j]][2];

f += f2[i];

if (f < bestf) {

swap(i, j);

BackTrack(i + 1);

swap(i, j);

}

f1 -= M[x[j]][1];

f -= f2[i];

}

}

}

void main() {

n = 3;

bestf = INT_MAX;

M[1][1] = 2;M[1][2] = 1;

M[2][1] = 3;M[2][2] = 1;

M[3][1] = 2;M[3][2] = 3;

for (int i = 0; i <= n; i++) {

f2[i] = 0;

x[i] = i;

}

BackTrack(1);

printf("%d\n", bestf);

for (int i = 1; i <= n; i++) {

printf("%d ", bestx[i]);

if (i != n)

printf("-> ");

}

printf("\n");

system("pause");

}

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值