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

问题描述

在这里插入图片描述

题目分析

这道题目也是一个比较经典的回溯法问题,但是这个问题和我们之前说的装载问题
不同的是,这里面的每一种作业我们都要安排,而不是找其中的子集,而装载问题才是一个找子集的问题。所以根据回溯法框架里的内容,对于这种解空间中必须包含全部而不是找子集的情况,我们应该使用的解空间是排列树。结构如下图所示:

在这里插入图片描述我们可以将这些序列看成是在x=(1,2,3)的基础上经过各种不同作业的两两交换而得到的不同调度方案。在回溯法的框架中我们也提到了,解空间为排列树的问题是通过不断交换来进行选择不同情况的,在回溯的时候还需要将二者交换回来。
在这里面我们需要声明一个f2的一维数组表示机器2完成的时间,f1表示机器1完成的时间,M是一个二维数组,表示所有作业的调度时间。f2之所以用数组表示,是因为我们其实在过程中f2存储的是机器1完成的时间+机器2完成的时间(因为机器1完成之后机器2才能完成,所以可以统一存储)。但是后一项作业的结束时间取决于上一项作业的结束时间,如果上一项还没完成,则机器2一定被占用着,当前工作也就不能完成,这都实现中的一些细节,等下我们会看到具体如何展开。可以看代码中的注释.

代码

#include <iostream>
using namespace std;
class Flowshop()
{
    //参数是作业调度时间表,作业数和当前的做优调度
    friend Flow(int **,int,int []);
    private:
        void Backtrack(int i);//参数是现在要执行的作业次序,不是具体的哪个作业
        int **M,//各作业所需的处理时间
        int *x,//作业的调度
        int *bestx,//当前的最优作业调度
        int *f2,//机器2完成处理时间,这里之所以声明为数组是因为f2和i有关系,我们会记录下某一工作结束后的完成时间储存在f2[i]里
        int f1,//机器1完成处理时间
        int f,//完成时间和
        int bestf,//当前最优值,
        int n;//作业数
};
void Flowshop::Backtrack(int i)
{
    if(i > n)
    //到达了叶节点,我们需要更新当前最优调度和最优值
    {
        for(int j = 1;j < n;j++)
        {
            bestx[j] = x[j];
        }
        bestf = f;
    }
    else
    {
        //这里的重点是这个j
        //j表示的是具体的工作,而i是作业分量,即我们现在正在要做第i个作业,于是我们选择作业j作为第i个要进行的作业
        for(int j = i;j < n;j++)
        {
            //机器1完成时间我们只需要简单进行加和
            f1 += M[x[j]][1];
            //机器2完成时间取决于上一个工作的完成时间,i-1不完成我们无法完成i
            f2[i] = ((f2[i-1] > f1) ? f2[i-1] : f1) + M[x[j]][2];
            f += f2[i];
            if(f < bestf)
            {
                swap(x[i],x[j]);
                Backtrack(i + 1);
                swap(x[i],x[j]);
            }
            f1 -= M[x[j]][1];
            f -= f2[i];
        }
    }
}
int Flow(int **M,int n,int bestx[])
{
    int ub = INT_MAX;
    Flowshop X;
    X.x = new int [n + 1];
    X.f2 = new int [n + 1];
    X.M = M;
    X.n = n;
    X.bestx = bestx;
    X.bestf = ub;
    X.f1 = 0;
    X.f = 0;
    for(int i = 0;i <= n;i++)
    {
        X.f2[i] = 0;
        X.x[i] = i;
    }
    X.Backtrack(1);
    delete[] X.x;
    delete[] X.f2;
    return X.bestf;
}

总结

由于这是一个排列树解空间,所以我们的时间复杂应该为O(n!)
(排列组合问题)

原创文章 101 获赞 13 访问量 2325

猜你喜欢

转载自blog.csdn.net/weixin_44755413/article/details/105845732