批处理作业调度问题 (回溯法)

目录

一、问题解析

二、实例剖析

三、算法思路

四、代码实现

结果:

总结


前言

问题】n 个作业{1, 2, …, n}要在两台机器上处理,每个作业必须先由机器 1 处理,再由机器 2 处理,机器 1 处理作业i所需时间为 ai,机器 2 处理作业 i 所需时间为 bi(1 ≤ i ≤ n),批处理作业调度问题(batch-job scheduling problem)要求确定这 n 个作业的最优处理顺序,使得从第 1 个作业在机器 1 上处理开始,到最后一个作业在机器 2 上处理结束所需时间最少。

一、问题解析

想法】显然,批处理作业的一个最优调度应使机器 1 没有空闲时间,且机器 2的空闲时间最小。

  1. 存在一个最优作业调度使得在机器 1 和机器 2 上作业以相同次序完成
  2. 由于是一种作业调度顺序的方案,因此该问题的解空间树是排列树

二、实例剖析

例如,有三个作业{1, 2, 3},在机器 1 上所需的处理时间为(2, 5, 4),在机器 2上所需的处理时间为(3, 2, 1),则存在 6 种可能的调度方案:{(1, 2, 3), (1, 3, 2), (2, 1, 3), (2, 3, 1), (3, 1, 2), (3, 2, 1)},相应的完成时间为{12, 13, 12, 14, 13, 16},最佳调度方案是(1, 2, 3)和(2, 1, 3),最短完成时间为 12。

其他情况如上类似,这里就不再赘述!!

三、算法思路

算法设数组a[n]存储 n 个作业在机器 1 上的处理时间,b[n]存储 n 个作业在机器 2 上的处理时间。设数组x[n]表示 n 个作业批处理的一种调度方案,其中x[i]表示第 i 个处理的作业编号,sum1[n]和sum2[n]保存在调度过程中机器 1 和机器 2的当前完成时间,其中sum1[i]表示在安排第 i 个作业后机器 1 的当前完成时间,sum2[i]表示在安排第 i 个作业后机器 2 的当前完成时间,且根据下式进行更新:

关键点:

⭐sum1[i] = sum1[i-1] + a[ x[i] ]

⭐sum2[i] = max(sum1[i], sum2[i-1]) +b[ x[i] ]

算法:回溯法求解批处理调度BatchJob

输入:n 个作业在机器 1 上的处理时间 a[n],在机器 2 上的处理时间 b[n]

输出:最短完成时间bestTime,最优调度序列 x[n]

1. 初始化解向量 x[n] = {-1};最短完成时间bestTime = MAX;

2. 初始化调度方案中机器 1 和机器 2 的完成时间:

sum1[n] = sum2[n] = {0}; i = 0;

3. 当 i >= 0 时调度第 i 个作业:

3.1 依次考察每一个作业,如果作业 x[i] 尚未处理,则转步骤 3.2,

否则尝试下一个作业,即 x[i]++;

3.2 处理作业 x[i]:

3.2.1  sum1[i]=sum1[i-1]+ a[x[i]];

3.2.2  sum2[i]=max{sum1[i], sum2[i-1]}+ b[x[i]];

四、代码实现

#include <iostream>
#include <vector>
#include <climits>

using namespace std;

int bestTime = INT_MAX;
vector<int> bestSchedule;
vector<int> currentSchedule;

void backtrack(vector<int>& a, vector<int>& b, vector<bool>& processed, vector<int>& sum1, vector<int>& sum2, int index, int n) {
    if (index == n) {
        if (sum2[n-1] < bestTime) {
            bestTime = sum2[n-1];
            bestSchedule = currentSchedule;
        }
        return;
    }

    for (int i = 0; i < n; i++) {
        if (!processed[i]) {
            processed[i] = true;
            currentSchedule[index] = i;
            sum1[index] = (index > 0 ? sum1[index-1] : 0) + a[i];
            sum2[index] = max(sum1[index], (index > 0 ? sum2[index-1] : 0)) + b[i];
            backtrack(a, b, processed, sum1, sum2, index + 1, n);
            processed[i] = false;
        }
    }
}

int batchJobScheduling(vector<int>& a, vector<int>& b) {
    int n = a.size();
    vector<bool> processed(n, false);
    vector<int> sum1(n, 0);
    vector<int> sum2(n, 0);
    currentSchedule.resize(n);

    backtrack(a, b, processed, sum1, sum2, 0, n);

    return bestTime;
}

int main() {
    vector<int> a = {2, 3, 1};
    vector<int> b = {3, 1, 2};

    int result = batchJobScheduling(a, b);
    cout << "Best processing time: " << result << endl;
    cout << "Best schedule: ";
    for (int job : bestSchedule) {
        cout << job << " ";
    }
    cout << endl;

    return 0;
}

结果:

第一行表示:所需的最短时间;第二行表示:最好的安排次序

总结

算法时间复杂度高,时间消耗太多了,在ACM上一直会超时,不如贪心法效率高。我是一个小菜鸡,欢迎各路大神批评指正!!

 

  • 26
    点赞
  • 19
    收藏
    觉得还不错? 一键收藏
  • 2
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值