1、问题描述

设有n个独立的作业{1, 2, …, n}, 由m台相同的机器进行加工处理. 作业i所需时间为t i. 约定:任何作业可以在任何一台机器上加工处理, 但未完工前不允许中断处理,任何作业不能拆分成更小的子作业。要求给出一种作业调度方案,使所给的n 个作业在尽可能短的时间内由m台机器加工处理完成。 

 多机调度问题是一个NP完全问题,到目前为止还没有完全有效的解法。对于这类问题,用贪心选择策略有时可以设计出一个比较好的近似算法。

 2、贪心算法求解思路

 采用最长处理时间作业优先的贪心策略:
 当n≤m时, 只要将机器i的[0, ti]时间区间分配给作业i即可。
 当n>m时, 将n个作业依其所需的处理时间从大到小排序,然后依次将作业分配给空闲的处理机。

  具体代码如下:

package 贪心;

//public class Greedy
import java.util.ArrayList;
import java.util.Collections;
import java.util.LinkedList;
import java.util.List;

/**
 * @author 葛帅帅
 */
public class Greedy {
    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;
            if(time>times) return -1;
            if(time==times) return 0;
            return 1;

        }
    }
    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;
            if(avail<xs) return -1;
            if(avail==xs) return 0;
            return 1;
        }
    }
    public static int greedy(int[] a ,int m){
        int n=a.length;//a的下标从1开始,所以n(作业的数目)=a.length-1
        int sum=0;
        if(n<=m){
            for(int i=0;i<n;i++)
                sum+=a[i+1];
            System.out.println("为每个作业分别分配一台机器");
            return sum;
        }
        List<JobNode> d=new ArrayList<JobNode>();//d保存所有的作业
        for(int i=0;i<n;i++){//将所有的作业存入List中,每一项包含标号和时间
            JobNode jb=new JobNode(i+1,a[i]);
            d.add(jb);
        }
        Collections.sort(d);//对作业的List进行排序
        LinkedList<MachineNode> h=new LinkedList<MachineNode>();//h保存所有的机器
        for(int i=1;i<=m;i++){//将所有的机器存入LinkedList中
            MachineNode x=new MachineNode(i,0);//初始时,每台机器的空闲时间(完成上一个作业的时间)都为0
            h.add(x);
        }
        int test=h.size();
        for(int i=0;i<n;i++){
              Collections.sort(h);
            MachineNode x=h.peek();
            System.out.println("将机器"+x.id+"从"+x.avail+"到"+(x.avail+d.get(i).time)+"的时间段分配给作业"+d.get(i).id);
            x.avail+=d.get(i).time;
            sum=x.avail;
        }
        return sum;
    }
    public static void main(String[] args) {
        int[] a={14,2,3,4,5,6,8,8,9};
              // 1,2,3,4,5,6,7 ,8,9
        int m=3;
        int sum=greedy(a,m);
        System.out.println("总时间为:"+sum);
    }
}
/**
 运行结果:
 将机器1从0到14的时间段分配给作业1
 将机器2从0到9的时间段分配给作业9
 将机器3从0到8的时间段分配给作业7
 将机器3从8到16的时间段分配给作业8
 将机器2从9到15的时间段分配给作业6
 将机器1从14到19的时间段分配给作业5
 将机器2从15到19的时间段分配给作业4
 将机器3从16到19的时间段分配给作业3
 将机器3从19到21的时间段分配给作业2
 总时间为:21
 */