批处理作业问题——分支限界法

#include <iostream>
using namespace std;

//最小堆的插入与删除
template<class T>
class MinHeap
{
    template<class Type>
    friend class Graph;

    public:
        MinHeap(int maxheapsize = 10);
        ~MinHeap(){delete []heap;}

        int Size() const{return currentsize;}
        MinHeap<T>& Insert(const T& x);
        MinHeap<T>& DeleteMin(T &x);


    private:
        int currentsize, maxsize;
        T *heap;
};

template <class T>
MinHeap<T>::MinHeap(int maxheapsize)//构造函数 没有返回值类型
{
    maxsize = maxheapsize;
    heap = new T[maxsize + 1];
    currentsize = 0;

}

template<class T>
MinHeap<T>&  MinHeap<T>::Insert(const T& x)//返回类型是MinHeap<T>
{
    if(currentsize == maxsize)
    {
        return *this;
    }
    int i = ++currentsize;
    while(i != 1 && x < heap[i/2])
    {
        heap[i] = heap[i/2];
        i /= 2;
    }

    heap[i] = x;
    return *this;
}

template<class T>
MinHeap<T>&  MinHeap<T>::DeleteMin(T& x) //返回类型是MinHeap<T>
{
    if(currentsize == 0)
    {
        cout<<"Empty heap!"<<endl;
        return *this;
    }

    x = heap[1];

    T y = heap[currentsize--];
    int i = 1, ci = 2;
    while(ci <= currentsize)
    {
        if(ci < currentsize && heap[ci] > heap[ci + 1])
        {
            ci++;
        }

        if(y <= heap[ci])
        {
            break;
        }
        heap[i] = heap[ci];
        i = ci;
        ci *= 2;
    }

    heap[i] = y;
    return *this;
}




//开始作业调度
class Flowshop;
class MinHeapNode
{
    friend Flowshop;
    public:
        operator int() const
        {
            return bb;
        }
    private:
        void Init(int);
        void NewNode(MinHeapNode,int,int,int,int);
        int s,          //已安排作业数
            f1,         //机器1上最后完成时间
            f2,         //机器2上最后完成时间
            sf2,        //当前机器2上完成时间和
            bb,         //当前完成时间和下界
            *x;         //当前作业调度
};

class Flowshop
{
    friend int main(void);
    public:
        int BBFlow(void);
    private:
        int Bound(MinHeapNode E,int &f1,int &f2,bool **y);
        void Sort(void);
        int n,          //作业数
            ** M,       //各作业所需的处理时间数组
            **b,        //各作业所需的处理时间排序数组
            **a,        //数组M和b的对应关系数组
            *bestx,     //最优解
            bestc;      //最小完成时间和
        bool **y;       //工作数组
};

template <class Type>
inline void Swap(Type &a, Type &b);

int main()
{
    int n=3,bf;
    int M1[3][2]={{2,1},{3,1},{2,3}};

    int **M = new int*[n];
    int **b = new int*[n];
    int **a = new int*[n];
    bool **y = new bool*[n];
    int *bestx = new int[n];

    for(int i=0;i<=n;i++)
    {
        M[i] = new int[2];
        b[i] = new int[2];
        a[i] = new int[2];
        y[i] = new bool[2];
    }
    cout<<"各作业所需要的处理时间"<<endl;
    cout<<"     机器1 机器2  "<<endl;

    for(int i=0;i<n;i++)
    {
        for(int j=0;j<2;j++)
        {
            M[i][j]=M1[i][j];
        }
    }

    for(int i=0;i<n;i++)
    {
        cout<<"作业"<<i+1<<":";
        for(int j=0;j<2;j++)
        cout<<M[i][j]<<"      ";
        cout<<endl;

    }
    cout<<endl;

    Flowshop flow;
    flow.n = n;
    flow.M = M;
    flow.b = b;
    flow.a = a;
    flow.y = y;
    flow.bestx = bestx;
    flow.bestc = 1000;//给初值

    flow.BBFlow();

    cout<<"最少花费是:"<<flow.bestc<<endl;
    cout<<"最优解空间是:";

    for(int i=0;i<n;i++)
    {
        cout<<(flow.bestx[i]+1)<<" ";
    }
    cout<<endl;

    for(int i=0;i<n;i++)
    {
        delete[] M[i];
        delete[] b[i];
        delete[] a[i];
        delete[] y[i];
    }
    return 0;
}

//最小堆节点初始化
void MinHeapNode::Init(int n)
{
    x = new int[n];
    for(int i=0; i<n; i++)
    {
        x[i] = i;
    }
    s = 0;
    f1 = 0;
    f2 = 0;
    sf2 = 0;
    bb = 0;
}

//最小堆新节点
void MinHeapNode::NewNode(MinHeapNode E,int Ef1,int Ef2,int Ebb,int n)
{
    x = new int[n];
    for(int i=0; i<n; i++)
    {
        x[i] = E.x[i];
    }
    f1 = Ef1;
    f2 = Ef2;
    sf2 = E.sf2 + f2;
    bb = Ebb;
    s =  E.s + 1;
}

//对各作业在机器1和2上所需时间排序 排序成非递减
void Flowshop::Sort(void)
{
    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],b[k-1][j]);
                    Swap(c[k],c[k-1]);
                }
            }
        }

        for(int i=0; i<n; i++)
        {
            a[c[i]][j] = i;
        }
    }

    delete []c;
}

//计算完成时间和下界
int Flowshop::Bound(MinHeapNode E,int &f1,int &f2,bool **y)
{
    for(int k=0; k<n; k++)
    {
        for(int j=0; j<2; j++)
        {
            y[k][j] = false;
        }
    }

    for(int k=0; k<=E.s; k++)
    {
        for(int j=0; j<2; j++)
        {
            y[a[E.x[k]][j]][j] = true;
        }
    }

    f1 = E.f1 + M[E.x[E.s]][0];
    f2 = ((f1>E.f2)?f1:E.f2)+M[E.x[E.s]][1];
    int sf2 = E.sf2 + f2;
    int s1 = 0,s2 = 0,k1 = n-E.s,k2 = n-E.s,f3 = f2;

    //计算s1的值
    for(int j=0; j<n; j++)
    {
        if(!y[j][0])
        {
            k1--;
            if(k1 == n-E.s-1)
            {
                f3 = (f2>f1+b[j][0])?f2:f1+b[j][0];
            }
            s1 += f1+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);
}

//解批处理作业调度问题的优先队列式分支限界法
int Flowshop::BBFlow(void)
{
    Sort();//对各作业在机器1和2上所需时间排序
    MinHeap<MinHeapNode> H(1000);

    MinHeapNode E;
    //初始化
    E.Init(n);
    //搜索排列空间树
    while(E.s<=n)
    {
        //叶节点
        if(E.s == n)
        {
            if(E.sf2<bestc)
            {
                bestc = E.sf2;
                for(int i=0; i<n; i++)
                {
                    bestx[i] = E.x[i];
                }
            }
            delete []E.x;
        }
        else//产生当前扩展节点的儿子节点
        {
            for(int i=E.s; i<n; i++)
            {
                Swap(E.x[E.s],E.x[i]);
                int f1,f2;
                int bb = Bound(E,f1,f2,y);
                if(bb<bestc)
                {
                    //子树可能含有最优解
                    //节点插入最小堆
                    MinHeapNode N;
                    N.NewNode(E,f1,f2,bb,n);
                    H.Insert(N);
                }
                Swap(E.x[E.s],E.x[i]);
            }
            delete []E.x;//完成节点扩展
        }
        if(H.Size() == 0)
        {
            break;
        }
        H.DeleteMin(E);//取下一扩展节点
    }
    return bestc;
}

template <class Type>
inline void Swap(Type &a, Type &b)
{
    Type temp=a;
    a=b;
    b=temp;
}
  • 0
    点赞
  • 8
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
好的,我可以为你介绍一下分支限界法和装载问题的相关内容。 分支限界法是一种求解最优化问题的算法,通过不断扩展解空间,逐步缩小搜索范围,最终找到最优解。它的核心思想是将问题划分成许多子问题,并采用优先队列(或优先级队列)来维护待扩展的子问题集合,每次取出优先级最高的子问题进行扩展,直到找到最优解或者队列为空。 而装载问题是一种典型的分支限界法应用场景,它的主要思想是在给定的一些物品中选出尽可能多的物品放入容量为C的背包中,使得背包中物品的总重量不超过C,并且背包中物品的总价值最大。这个问题可以通过分支限界法来求解。 下面是一个简单的 Java 代码实现,用于解决装载问题: ```java import java.util.*; public class BranchAndBound { public static void main(String[] args) { int[] w = {5, 10, 20, 30}; // 物品的重量 int[] v = {50, 60, 140, 120}; // 物品的价值 int C = 50; // 背包的容量 int n = w.length; // 物品的数量 int[] x = new int[n]; // 记录每个物品是否被选中 PriorityQueue<Node> queue = new PriorityQueue<>(); queue.offer(new Node(-1, 0, 0)); // 将根节点加入队列中 while (!queue.isEmpty()) { Node node = queue.poll(); // 取出优先级最高的子问题 if (node.level == n - 1) { // 如果是叶子节点,更新最优解 for (int i = 0; i < n; i++) { x[i] = node.x[i]; } } else { int level = node.level + 1; int weight = node.weight; int value = node.value; if (weight + w[level] <= C) { // 左子节点表示选中当前物品 int[] left = Arrays.copyOf(node.x, n); left[level] = 1; queue.offer(new Node(level, weight + w[level], value + v[level], left)); } // 右子节点表示不选当前物品 queue.offer(new Node(level, weight, value, node.x)); } } int max = 0; for (int i = 0; i < n; i++) { if (x[i] == 1) { System.out.println("第" + (i + 1) + "个物品被选中"); max += v[i]; } } System.out.println("最大价值为:" + max); } // 子问题节点 static class Node implements Comparable<Node> { int level; // 当前节点所在的层级 int weight; // 当前节点的背包重量 int value; // 当前节点的背包价值 int[] x; // 记录每个物品是否被选中 public Node(int level, int weight, int value) { this.level = level; this.weight = weight; this.value = value; this.x = new int[0]; } public Node(int level, int weight, int value, int[] x) { this.level = level; this.weight = weight; this.value = value; this.x = x; } @Override public int compareTo(Node o) { return o.value - this.value; // 根据价值进行优先级比较 } } } ``` 希望这个简单的例子能帮助你更好地理解分支限界法和装载问题。如果你还有其他问题或者疑惑,欢迎随时向我提出。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值