zoukankan      html  css  js  c++  java
  • 批处理作业调度_分支限界法

    一、    问题描述

        给定 n 个作业的集合 j = {j1, j2, …, jn}。每一个作业 j[i] 都有两项任务分别在两台机器上完成。每一个作业必须先由机器1 处理,然后由机器2处理。作业 j[i] 需要机器 j 的处理时间为 t[j][i] ,其中i = 1, 2, …, n, j = 1, 2。对于一个确定的作业 调度,设F[j][i]是作业 i 在机器 j 上的完成处理的时间。所有作 业在机器2上完成处理的时间之和 f = sigma F[2][i] 称为该作业 调度的完成时间之和。

    批处理作业调度问题要求对于给定的 n 个作业,制定最佳作业调度 方案,使其完成时间和达到最小。

    二、  解题思路及所选算法策略的可行性分析

       用优先队列式分支限界法解决此问题。由于要从n个作业的所有排列中找出有最小完成时间和的作业调度,所以批处理作业调度问题的解空间树是一颗排列树。对于批处理作业调度问题,可以证明存在最佳作业调度使得在机器1和机器2上作业以相同次序完成(因为每个作业必须先在机器1上完成作业才能在机器2上进行作业)。

        如果对于未安排的作业,对于其中一个作业,每当该作业在机器1上完成处理后都能立即在机器2上开始处理,则机器1没有空闲时间,达到满工作状态,将此情况的未安排作业在机器2上的工作时间总和记为S1,同理将机器2满工作状态的情况下的工作时间总和记为S2,则必有:

        所有作业机器2上完工时间和 >= 已安排作业机器2上完工时间和 + max{S1,S2}

    其中当未安排作业按照在机器1、2上工作时间非递减顺序进行调度时,S1和S2同时取得极小值且和调度无关,由此可作为分支限界法中的限界函数。

    伪代码描述及复杂度分析

    bbFlow(){

        对各作业在机器1和2上作旭时间排序

        do{

            if(到达叶结点){

                if(当前作业安排机器2上完成时间和 < bestc){

                    更新bestc;

                    更新最优解;

                }

            }else{

                For(int i=enode.已安排作业数; i<总作业数; i++){

                    求得当前下届bb;

                    If(bb < bestc){

                        结点插入最小堆;

                    }

                }

            }

            取下一个拓展结点;

        }while(enode!=null&&enode.s<=n)

    }

    三、  代码实现

    package 分支限界法;
    
    public class Nodes implements Comparable {
        int s;//已安排作业数
        int sf2;//当前机器2上的完成时间和
        int bb;//当前完成时间和下界
        int[] f;//f[1]机器1上最后完成时间,f[2]机器2上最后完成时间
        int[] x;//当前作业调度
        
        public Nodes(int n){
            //最小堆结点初始化
            x=new int[n];
            for(int i=0;i<n;i++)
                x[i]=i;
            s=0;
            f=new int[3];
            f[1]=0;
            f[2]=0;
            sf2=0;
            bb=0;
        }
        
        public Nodes(Nodes e,int[] ef,int ebb,int n){
            //最小堆新结点
            x=new int[n];
            for(int i=0;i<n;i++)
                x[i]=e.x[i];
            f=ef;
            sf2=e.sf2+f[2];
            bb=ebb;
            s=e.s+1;
        }
     
        @Override
        public int compareTo(Object o) {
            int xbb=((Nodes) o).bb;
            if(bb<xbb) return -1;
            if(bb==xbb) return 0;
            return 1;
        }
    }
    
    public class BBFlow {
        public int n;//作业数
        public int bestc;//最小完成时间和
        public int [][]m;//n个作业所需的处理时间数组
        public int [][]b;//n个作业所需的处理时间排序数组
        public int[][] a;//数组m和b的对应关系数组
        public int[] bestx;//最优解
        public boolean[][] y;//工作数组
        
        public BBFlow(int n,int[][] m){
            this.n=n;
            bestc=10000;
            this.m=m;
            b=new int[n][2];
            a=new int[n][2];
            bestx=new int[n];
            y=new boolean[n][2];
        }
        public void swap(int[][] b,int i,int j,int k,int t){
            int temp=b[i][j];
            b[i][j]=b[k][t];
            b[k][t]=temp;
        }
        public void swap(int[] x,int i,int j){
            int temp=x[i];
            x[i]=x[j];
            x[j]=temp;
        }
        /**
         * 对n个作业在机器1和2上所需时间排序
         */
        public void sort(){
            int[] c=new int[n];
            for(int j=0;j<2;j++){
                for(int i=0;i<n;i++){
                    b[i][j]=m[i][j];
                    c[i]=i;
                }
                for(int i=0;i<n-1;i++){
                    for(int k=n-1;k>i;k--){
                        if(b[k][j]<b[k-1][j]){
                            swap(b,k,j,k-1,j);
                            swap(c,k,k-1);
                        }
                    }
                }
                for(int i=0;i<n;i++)
                    a[c[i]][j]=i;
            }
        }
        /**
         * 计算完成时间和下界
         * @param enode
         * @param f
         * @return
         */
        public int bound(Nodes enode,int[] f){
            for(int k=0;k<n;k++){
                for(int j=0;j<2;j++){
                    y[k][j]=false;
                }
            }
            for(int k=0;k<enode.s;k++){
                for(int j=0;j<2;j++){
                    y[a[enode.x[k]][j]][j]=true;
                }
            }
            f[1]=enode.f[1]+m[enode.x[enode.s]][0];
            f[2]=((f[1]>enode.f[2])?f[1]:enode.f[2])+m[enode.x[enode.s]][1];
            int sf2=enode.sf2+f[2];
            int s1=0;
            int s2=0;
            int k1=n-enode.s;
            int k2=n-enode.s;
            int f3=f[2];
            //计算s1的值
            for(int j=0;j<n;j++){
                if(!y[j][0]){
                    k1--;
                    if(k1==n-enode.s-1)
                        f3=(f[2]>f[1]+b[j][0])?f[2]:f[1]+b[j][0];
                    s1+=f[1]+k1*b[j][0];
                }
            }
            //计算s2的值
            for(int j=0;j<n;j++){
                if(!y[j][1]){
                    k2--;
                    s1+=b[j][1];
                    s2+=f3+k2*b[j][1];
                }
            }
            //返回完成时间和下界
            return  sf2+((s1>s2)?s1:s2);
        }
        /**
         * 优先队列式分支限界法解批处理作业调度问题
         * @param nn
         * @return
         */
        public int bbFlow(int nn){
            n=nn;
            sort();//对n个作业在机器1和2上所需时间排序
            LinkedList<Nodes> heap=new LinkedList<Nodes>();
            Nodes enode =new Nodes(n);
            //搜索排列空间树
            do{
                if(enode.s==n){
                    //叶节点
                    if(enode.sf2<bestc){
                        bestc=enode.sf2;
                        for(int i=0;i<n;i++){
                            bestx[i]=enode.x[i];
                        }
                    }
                }else{
                    //产生当前扩展结点的儿子结点
                    for(int i=enode.s;i<n;i++){
                        swap(enode.x,enode.s,i);
                        int[] f=new int[3];
                        int bb=bound(enode,f);
                        if(bb<bestc){
                            //子树可能含有最优解
                            //结点插入最小堆
                            Nodes node=new Nodes(enode,f,bb,n);
                            heap.add(node);
                            Collections.sort(heap);
                        }
                        swap(enode.x,enode.s,i);
                    }//完成结点扩展
                }
                //取下一个扩展结点
                enode=heap.poll();
            }while(enode!=null&&enode.s<=n);
            return bestc;
        }
     
        
        
        public static void main(String[] args) {
            int n=3;
            int[][] m={{2,1},{3,1},{2,3}};//m的下标从0开始
            BBFlow f=new BBFlow(n,m);
            f.bbFlow(n);
            System.out.println("最优批处理作业调度顺序为:");
            for(int i=0;i<n;i++)
                System.out.print((f.bestx[i]+1)+" ");
            System.out.println();
            System.out.println("最优调度所需的最短时间为:"+f.bestc);
        }
    }
    
    /*************************
    *运行结果
    *最优批处理作业调度顺序为:
    *1 3 2 
    *最优调度所需的最短时间为:18
    *************************/

     

  • 相关阅读:
    java 自定义表单 动态表单 表单设计器 工作流引擎 flowable 设计方案
    设置Springboot返回jackson数据序列化
    SpringCloud Alibaba 报 AbstractMethodError 是版本兼容问题导致
    Springboot进阶JDBC、Druid、Mybatis、Swagger、SpringMVC、Mail
    java 自定义表单 动态表单 表单设计器 工作流引擎 flowable 项目源码
    springcloud Alibaba 微服务 flowable 工作流 自定义表单 vue.js前后分离
    ClassLoader读取文件,springboot打jar包后读取不到
    Nginx/Tomcat/Apache的优缺点和区别
    Swagger3 相比2配置变了
    webloginc配置项目根目录
  • 原文地址:https://www.cnblogs.com/LieYanAnYing/p/12038398.html
Copyright © 2011-2022 走看看