求解多机作业调度问题

一、多机作业调度问题描述

有m台相同的机器,需要处理n个独立的作业,作业i所需的处理时间为t[i]。 每个作业都可以在任何一台机器上加工处理,但未完工之前不允许中断处理。任何作业不能拆分成更小的作业。 如何对作业进行调度,使得所给的n个作业由m台机器在尽可能短的时间内加工处理完成。

二、解题思路

使用贪心算法求解多机调度问题,其策略是耗时最长的作业优先,把“处理时间最长的作业”分配给“最先空闲的机器”,这样可以保证处理时间长的作业优先处理,从而在整体上获得尽可能短的处理时间。按照“耗时最长的作业优先处理”的策略:

当机器数m>=作业数n时,只要将机器 i 的[0,t[i]]时间区间分配给作业 i 即可。这种情况下,耗时最长的作业的处理时间就是所求的最短时间。

当机器数m<作业数n时,按照如下步骤处理:

第1步:将n个作业按其所需处理时间从大到小降序排列;

第2步:将m个机器按照工作时长从小到大升序排列;

第3步:将“耗时最长的作业”分配给“最先空闲的机器”,增加该机器的工作时长。

重复第二步和第三步,直到所有作业都被处理。这种情况下,累加耗时最长的机器的工作时长就是所求的最短时间。

三、Java编码实现

根据上一节的算法步骤,我们很容易就能编程解决多机作业调度问题。

具体实现如下:

package com.test.algorithm.multimachinealgothrim;

import java.util.ArrayList;
import java.util.Collections;
import java.util.LinkedList;
import java.util.List;
import java.util.Objects;


public class MultiMachineSchedule {

    /**
     * 贪心方法求解结果
     *
     * @param a 作业列表
     * @param m 机器数
     * @return 总耗时
     */
    public static int greedy(int[] a, int m) {
        int n = a.length;
        int total = 0;
        if (n <= m) {
            for (int i = 0; i < n; i++) {
                if (total < a[i]) {
                    total = a[i];
                }
            }
            System.out.println("为每个作业分别分配一台机器");
            return total;
        }

        List<JobNode> jobNodes = new ArrayList<>(); // jobNodes保存所有的作业
        for (int i = 0; i < n; i++) { // 将所有的作业存入List中,每一项包含标号和时间
            JobNode jb = new JobNode(i + 1, a[i]);
            jobNodes.add(jb);
        }
        Collections.sort(jobNodes); // 按照作业时长降序排列
//        jobNodes.forEach(jobNode -> System.out.println(jobNode.id + " : " + jobNode.time));

        LinkedList<MachineNode> machineNodes = new LinkedList<>(); // machineNodes保存所有的机器
        for (int i = 0; i < m; i++) { // 将所有的机器存入LinkedList中
            MachineNode x = new MachineNode(i + 1, 0); // 初始时,每台机器的空闲时间(完成上一个作业的时间)都为0
            machineNodes.add(x);
        }

        for (int i = 0; i < n; i++) {
            Collections.sort(machineNodes); // 按照机器工作时长升序排列
//            machineNodes.forEach(machineNode -> System.out.println(machineNode.id + " : " + machineNode.avail));
            MachineNode machineNode = machineNodes.peek(); // 取出工作时长最小的机器节点
            System.out.println(
                    "机器: " + machineNode.id +
                    ", 时段: " + machineNode.avail + "到" + (machineNode.avail + jobNodes.get(i).time) +
                    ", 分配作业: " + jobNodes.get(i).id +
                    ", 作业时长: " + jobNodes.get(i).time
            );
            machineNode.avail += jobNodes.get(i).time;
        }

        Collections.sort(machineNodes); // 按照机器工作时长升序排列
        MachineNode machineNode = machineNodes.peekLast(); // 取出工作时长最大的机器节点
        if (Objects.nonNull(machineNode)) {
            total = machineNode.avail;
        }

        return total;
    }

    /**
     * 作业节点
     */
    public static class JobNode implements Comparable {
        int id; // 作业标号
        int time; // 作业时长

        public JobNode(int id, int time) {
            this.id = id;
            this.time = time;
        }

        @Override
        public int compareTo(Object x) { // 按作业时长降序排列
            int times = ((JobNode) x).time;
            return Integer.compare(times, time);
        }
    }

    /**
     * 机器节点
     */
    public static class MachineNode implements Comparable {
        int id; // 机器标号
        int avail; // 机器工作时长

        public MachineNode(int id, int avail) {
            this.id = id;
            this.avail = avail;
        }

        @Override
        public int compareTo(Object o) { // 按照工作时长升序排列,LinkedList的first为最小的
            int xs = ((MachineNode) o).avail;
            return Integer.compare(avail, xs);
        }
    }

    public static void main(String[] args) {
        // 作业耗时列表
        int[] a = {5, 4, 2, 14, 16, 6, 5, 3};
//        int[] a = {5, 4, 2};
        // 机器个数
        int m = 3;
        int total = MultiMachineSchedule.greedy(a, m);
        System.out.println("总时间为:" + total);
    }
}

运行结果为:

机器: 1, 时段: 0到16, 分配作业: 5, 作业时长: 16
机器: 2, 时段: 0到14, 分配作业: 4, 作业时长: 14
机器: 3, 时段: 0到6, 分配作业: 6, 作业时长: 6
机器: 3, 时段: 6到11, 分配作业: 1, 作业时长: 5
机器: 3, 时段: 11到16, 分配作业: 7, 作业时长: 5
机器: 2, 时段: 14到18, 分配作业: 2, 作业时长: 4
机器: 3, 时段: 16到19, 分配作业: 8, 作业时长: 3
机器: 1, 时段: 16到18, 分配作业: 3, 作业时长: 2
总时间为:19

  • 4
    点赞
  • 13
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值