0040算法笔记——【分支限界法】批处理作业调度问题

      问题描述

     给定n个作业的集合{J1,J2,…,Jn}。每个作业必须先由机器1处理,然后由机器2处理。作业Ji需要机器j的处理时间为tji。对于一个确定的作业调度,设Fji是作业i在机器j上完成处理的时间。所有作业在机器2上完成处理的时间和称为该作业调度的完成时间和。

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

      例:设n=3,考虑以下实例:


     这3个作业的6种可能的调度方案是1,2,3;1,3,2;2,1,3;2,3,1;3,1,2;3,2,1;它们所相应的完成时间和分别是19,18,20,21,19,19。易见,最佳调度方案是1,3,2,其完成时间和为18。

     限界函数

     批处理作业调度问题要从n个作业的所有排列中找出具有最小完成时间和的作业调度,所以如图,批处理作业调度问题的解空间是一颗排列树     

     在作业调度问相应的排列空间树中,每一个节点E都对应于一个已安排的作业集。以该节点为根的子树中所含叶节点的完成时间和可表示为:


     设|M|=r,且L是以节点E为根的子树中的叶节点,相应的作业调度为{pk,k=1,2,……n},其中pk是第k个安排的作业。如果从节点E到叶节点L的路上,每一个作业pk在机器1上完成处理后都能立即在机器2上开始处理,即从pr+1开始,机器1没有空闲时间,则对于该叶节点L有:

注:(n-k+1)t1pk,因为是完成时间和,所以,后续的(n-k+1)个作业完成时间和都得算上t1pk

     如果不能做到上面这一点,则s1只会增加,从而有:

     类似地,如果从节点E开始到节点L的路上,从作业pr+1开始,机器2没有空闲时间,则:


     同理可知,s2是的下界。由此得到在节点E处相应子树中叶节点完成时间和的下界是:


     注意到如果选择Pk,使t1pk在k>=r+1时依非减序排列,S1则取得极小值。同理如果选择Pk使t2pk依非减序排列,则S2取得极小值。 


     这可以作为优先队列式分支限界法中的限界函数。 

     算法描述

      算法中用最小堆表示活节点优先队列。最小堆中元素类型是MinHeapNode。每一个MinHeapNode类型的节点包含域x,用来表示节点所相应的作业调度。s表示该作业已安排的作业时x[1:s]。f1表示当前已安排的作业在机器1上的最后完成时间;f2表示当前已安排作业在机器2上的完成时间;sf2表示当前已安排的作业在机器2上的完成时间和;bb表示当前完成时间和下界。二维数组M表示所给的n个作业在机器1和机器2所需的处理时间。在类Flowshop中用二维数组b存储排好序的作业处理时间。数组a表示数组M和b的对应关系。算法Sort实现对各作业在机器1和2上所需时间排序。函数Bound用于计算完成时间和下界。

     函数BBFlow中while循环完成对排列树内部结点的有序扩展。在while循环体内算法依次从活结点优先队列中取出具有最小bb值(完成时间和下界)的结点作为当前扩展结点,并加以扩展。 算法将当前扩展节点E分两种情形处理:

 1)首先考虑E.s=n的情形,当前扩展结点E是排列树中的叶结点。E.sf2是相应于该叶结点的完成时间和。当E.sf2 < bestc时更新当前最优值bestc和相应的当前最优解bestx。 

    2)当E.s<n时,算法依次产生当前扩展结点E的所有儿子结点。对于当前扩展结点的每一个儿子结点node,计算出其相应的完成时间和的下界bb。当bb < bestc时,将该儿子结点插入到活结点优先队列中。而当bb bestc时,可将结点node舍去。 

    算法具体实现如下:

     1、MinHeap2.h

  1. #include <iostream>   
  2.   
  3. template<class Type>  
  4. class Graph;  
  5.   
  6. template<class T>   
  7. class MinHeap   
  8. {   
  9.     template<class Type>  
  10.     friend class Graph;  
  11.     public:   
  12.         MinHeap(int maxheapsize = 10);   
  13.         ~MinHeap(){delete []heap;}   
  14.   
  15.         int Size() const{return currentsize;}   
  16.         T Max(){if(currentsize) return heap[1];}   
  17.   
  18.         MinHeap<T>& Insert(const T& x);   
  19.         MinHeap<T>& DeleteMin(T &x);   
  20.   
  21.         void Initialize(T x[], int size, int ArraySize);   
  22.         void Deactivate();   
  23.         void output(T a[],int n);  
  24.     private:   
  25.         int currentsize, maxsize;   
  26.         T *heap;   
  27. };   
  28.   
  29. template <class T>   
  30. void MinHeap<T>::output(T a[],int n)   
  31. {   
  32.     for(int i = 1; i <= n; i++)   
  33.     cout << a[i] << " ";   
  34.     cout << endl;   
  35. }   
  36.   
  37. template <class T>   
  38. MinHeap<T>::MinHeap(int maxheapsize)   
  39. {   
  40.     maxsize = maxheapsize;   
  41.     heap = new T[maxsize + 1];   
  42.     currentsize = 0;   
  43. }   
  44.   
  45. template<class T>   
  46. MinHeap<T>& MinHeap<T>::Insert(const T& x)   
  47. {   
  48.     if(currentsize == maxsize)   
  49.     {   
  50.         return *this;   
  51.     }   
  52.     int i = ++currentsize;   
  53.     while(i != 1 && x < heap[i/2])   
  54.     {   
  55.         heap[i] = heap[i/2];   
  56.         i /= 2;   
  57.     }   
  58.   
  59.     heap[i] = x;   
  60.     return *this;   
  61. }   
  62.   
  63. template<class T>   
  64. MinHeap<T>& MinHeap<T>::DeleteMin(T& x)   
  65. {   
  66.     if(currentsize == 0)   
  67.     {   
  68.         cout<<"Empty heap!"<<endl;   
  69.         return *this;   
  70.     }   
  71.   
  72.     x = heap[1];   
  73.   
  74.     T y = heap[currentsize--];   
  75.     int i = 1, ci = 2;   
  76.     while(ci <= currentsize)   
  77.     {   
  78.         if(ci < currentsize && heap[ci] > heap[ci + 1])   
  79.         {   
  80.             ci++;   
  81.         }   
  82.   
  83.         if(y <= heap[ci])   
  84.         {   
  85.             break;   
  86.         }   
  87.         heap[i] = heap[ci];   
  88.         i = ci;   
  89.         ci *= 2;   
  90.     }   
  91.   
  92.     heap[i] = y;   
  93.     return *this;   
  94. }   
  95.   
  96. template<class T>   
  97. void MinHeap<T>::Initialize(T x[], int size, int ArraySize)   
  98. {   
  99.     delete []heap;   
  100.     heap = x;   
  101.     currentsize = size;   
  102.     maxsize = ArraySize;   
  103.   
  104.     for(int i = currentsize / 2; i >= 1; i--)   
  105.     {   
  106.         T y = heap[i];   
  107.         int c = 2 * i;   
  108.         while(c <= currentsize)   
  109.         {   
  110.             if(c < currentsize && heap[c] > heap[c + 1])   
  111.                 c++;   
  112.             if(y <= heap[c])   
  113.                 break;   
  114.             heap[c / 2] = heap[c];   
  115.             c *= 2;   
  116.         }   
  117.         heap[c / 2] = y;   
  118.     }   
  119. }   
  120.   
  121. template<class T>   
  122. void MinHeap<T>::Deactivate()   
  123. {   
  124.     heap = 0;   
  125. }   
#include <iostream>

template<class Type>
class Graph;

template<class T> 
class MinHeap 
{ 
	template<class Type>
	friend class Graph;
	public: 
		MinHeap(int maxheapsize = 10); 
		~MinHeap(){delete []heap;} 

		int Size() const{return currentsize;} 
		T Max(){if(currentsize) return heap[1];} 

		MinHeap<T>& Insert(const T& x); 
		MinHeap<T>& DeleteMin(T &x); 

		void Initialize(T x[], int size, int ArraySize); 
		void Deactivate(); 
		void output(T a[],int n);
	private: 
		int currentsize, maxsize; 
		T *heap; 
}; 

template <class T> 
void MinHeap<T>::output(T a[],int n) 
{ 
	for(int i = 1; i <= n; i++) 
	cout << a[i] << " "; 
	cout << endl; 
} 

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) 
{ 
	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) 
{ 
	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; 
} 

template<class T> 
void MinHeap<T>::Initialize(T x[], int size, int ArraySize) 
{ 
	delete []heap; 
	heap = x; 
	currentsize = size; 
	maxsize = ArraySize; 

	for(int i = currentsize / 2; i >= 1; i--) 
	{ 
		T y = heap[i]; 
		int c = 2 * i; 
		while(c <= currentsize) 
		{ 
			if(c < currentsize && heap[c] > heap[c + 1]) 
				c++; 
			if(y <= heap[c]) 
				break; 
			heap[c / 2] = heap[c]; 
			c *= 2; 
		} 
		heap[c / 2] = y; 
	} 
} 

template<class T> 
void MinHeap<T>::Deactivate() 
{ 
	heap = 0; 
} 
    2、6d9.cpp

  1. //批作业调度问题 优先队列分支限界法求解    
  2. #include "stdafx.h"   
  3. #include "MinHeap2.h"   
  4. #include <iostream>   
  5. using namespace std;  
  6.   
  7. class Flowshop;  
  8. class MinHeapNode  
  9. {  
  10.     friend Flowshop;  
  11.     public:  
  12.         operator int() const  
  13.         {  
  14.             return bb;  
  15.         }  
  16.     private:      
  17.         void Init(int);  
  18.         void NewNode(MinHeapNode,int,int,int,int);  
  19.         int s,          //已安排作业数   
  20.             f1,         //机器1上最后完成时间   
  21.             f2,         //机器2上最后完成时间   
  22.             sf2,        //当前机器2上完成时间和   
  23.             bb,         //当前完成时间和下界   
  24.             *x;         //当前作业调度   
  25. };  
  26.   
  27. class Flowshop  
  28. {  
  29.     friend int main(void);  
  30.     public:  
  31.         int BBFlow(void);  
  32.     private:  
  33.         int Bound(MinHeapNode E,int &f1,int &f2,bool **y);  
  34.         void Sort(void);  
  35.         int n,          //作业数   
  36.             ** M,       //各作业所需的处理时间数组   
  37.             **b,        //各作业所需的处理时间排序数组   
  38.             **a,        //数组M和b的对应关系数组   
  39.             *bestx,     //最优解   
  40.             bestc;      //最小完成时间和   
  41.         bool **y;       //工作数组   
  42. };  
  43.   
  44. template <class Type>  
  45. inline void Swap(Type &a, Type &b);  
  46.   
  47. int main()  
  48. {  
  49.     int n=3,bf;  
  50.     int M1[3][2]={{2,1},{3,1},{2,3}};  
  51.   
  52.     int **M = new int*[n];  
  53.     int **b = new int*[n];  
  54.     int **a = new int*[n];  
  55.     bool **y = new bool*[n];  
  56.     int *bestx = new int[n];    
  57.   
  58.     for(int i=0;i<=n;i++)  
  59.     {  
  60.         M[i] = new int[2];  
  61.         b[i] = new int[2];  
  62.         a[i] = new int[2];  
  63.         y[i] = new bool[2];  
  64.     }  
  65.     cout<<"各作业所需要的时间处理数组M(i,j)值如下:"<<endl;  
  66.   
  67.     for(int i=0;i<n;i++)  
  68.     {  
  69.         for(int j=0;j<2;j++)  
  70.         {  
  71.             M[i][j]=M1[i][j];  
  72.         }  
  73.     }  
  74.   
  75.     for(int i=0;i<n;i++)  
  76.     {  
  77.         cout<<"(";  
  78.         for(int j=0;j<2;j++)  
  79.         cout<<M[i][j]<<" ";  
  80.         cout<<")";  
  81.     }  
  82.     cout<<endl;  
  83.   
  84.     Flowshop flow;  
  85.     flow.n = n;  
  86.     flow.M = M;  
  87.     flow.b = b;  
  88.     flow.a = a;  
  89.     flow.y = y;  
  90.     flow.bestx = bestx;  
  91.     flow.bestc = 1000;//给初值   
  92.   
  93.     flow.BBFlow();  
  94.   
  95.     cout<<"最优值是:"<<flow.bestc<<endl;  
  96.     cout<<"最优调度是:";  
  97.   
  98.     for(int i=0;i<n;i++)  
  99.     {  
  100.         cout<<(flow.bestx[i]+1)<<" ";  
  101.     }  
  102.     cout<<endl;  
  103.   
  104.     for(int i=0;i<n;i++)  
  105.     {  
  106.         delete[] M[i];  
  107.         delete[] b[i];  
  108.         delete[] a[i];  
  109.         delete[] y[i];        
  110.     }  
  111.     return 0;  
  112. }  
  113.   
  114. //最小堆节点初始化   
  115. void MinHeapNode::Init(int n)  
  116. {  
  117.     x = new int[n];  
  118.     for(int i=0; i<n; i++)  
  119.     {  
  120.         x[i] = i;  
  121.     }  
  122.     s = 0;  
  123.     f1 = 0;  
  124.     f2 = 0;  
  125.     sf2 = 0;  
  126.     bb = 0;  
  127. }  
  128.   
  129. //最小堆新节点   
  130. void MinHeapNode::NewNode(MinHeapNode E,int Ef1,int Ef2,int Ebb,int n)  
  131. {  
  132.     x = new int[n];  
  133.     for(int i=0; i<n; i++)  
  134.     {  
  135.         x[i] = E.x[i];  
  136.     }  
  137.     f1 = Ef1;  
  138.     f2 = Ef2;  
  139.     sf2 = E.sf2 + f2;  
  140.     bb = Ebb;  
  141.     s =  E.s + 1;  
  142. }  
  143.   
  144. //对各作业在机器1和2上所需时间排序   
  145. void Flowshop::Sort(void)  
  146. {  
  147.     int *c = new int[n];  
  148.     for(int j=0; j<2; j++)  
  149.     {  
  150.         for(int i=0; i<n; i++)  
  151.         {  
  152.             b[i][j] = M[i][j];  
  153.             c[i] = i;  
  154.         }  
  155.   
  156.         for(int i=0; i<n-1; i++)  
  157.         {  
  158.             for(int k=n-1; k>i; k--)  
  159.             {  
  160.                 if(b[k][j]<b[k-1][j])  
  161.                 {  
  162.                     Swap(b[k][j],b[k-1][j]);  
  163.                     Swap(c[k],c[k-1]);  
  164.                 }  
  165.             }  
  166.         }     
  167.   
  168.         for(int i=0; i<n; i++)  
  169.         {  
  170.             a[c[i]][j] = i;  
  171.         }  
  172.     }  
  173.   
  174.     delete []c;  
  175. }  
  176.   
  177. //计算完成时间和下界   
  178. int Flowshop::Bound(MinHeapNode E,int &f1,int &f2,bool **y)  
  179. {  
  180.     for(int k=0; k<n; k++)  
  181.     {  
  182.         for(int j=0; j<2; j++)  
  183.         {     
  184.             y[k][j] = false;  
  185.         }  
  186.     }  
  187.   
  188.     for(int k=0; k<=E.s; k++)  
  189.     {  
  190.         for(int j=0; j<2; j++)  
  191.         {  
  192.             y[a[E.x[k]][j]][j] = true;  
  193.         }  
  194.     }  
  195.   
  196.     f1 = E.f1 + M[E.x[E.s]][0];  
  197.     f2 = ((f1>E.f2)?f1:E.f2)+M[E.x[E.s]][1];  
  198.     int sf2 = E.sf2 + f2;  
  199.     int s1 = 0,s2 = 0,k1 = n-E.s,k2 = n-E.s,f3 = f2;  
  200.   
  201.     //计算s1的值   
  202.     for(int j=0; j<n; j++)  
  203.     {  
  204.         if(!y[j][0])  
  205.         {  
  206.             k1--;  
  207.             if(k1 == n-E.s-1)  
  208.             {  
  209.                 f3 = (f2>f1+b[j][0])?f2:f1+b[j][0];  
  210.             }  
  211.             s1 += f1+k1*b[j][0];  
  212.         }  
  213.     }  
  214.   
  215.     //计算s2的值   
  216.     for(int j=0; j<n; j++)  
  217.     {     
  218.         if(!y[j][1])  
  219.         {  
  220.             k2--;  
  221.             s1 += b[j][1];  
  222.             s2 += f3 + k2*b[j][1];  
  223.         }  
  224.     }  
  225.   
  226.     //返回完成时间和下界   
  227.     return sf2 +((s1>s2)?s1:s2);  
  228. }  
  229.   
  230. //解批处理作业调度问题的优先队列式分支限界法   
  231. int Flowshop::BBFlow(void)  
  232. {  
  233.     Sort();//对各作业在机器1和2上所需时间排序   
  234.     MinHeap<MinHeapNode> H(1000);  
  235.   
  236.     MinHeapNode E;  
  237.     //初始化   
  238.     E.Init(n);  
  239.     //搜索排列空间树   
  240.     while(E.s<=n)  
  241.     {  
  242.         //叶节点   
  243.         if(E.s == n)  
  244.         {  
  245.             if(E.sf2<bestc)  
  246.             {  
  247.                 bestc = E.sf2;  
  248.                 for(int i=0; i<n; i++)  
  249.                 {  
  250.                     bestx[i] = E.x[i];  
  251.                 }  
  252.             }  
  253.             delete []E.x;  
  254.         }  
  255.         else//产生当前扩展节点的儿子节点   
  256.         {  
  257.             for(int i=E.s; i<n; i++)  
  258.             {  
  259.                 Swap(E.x[E.s],E.x[i]);  
  260.                 int f1,f2;  
  261.                 int bb = Bound(E,f1,f2,y);  
  262.                 if(bb<bestc)  
  263.                 {  
  264.                     //子树可能含有最优解   
  265.                     //节点插入最小堆   
  266.                     MinHeapNode N;  
  267.                     N.NewNode(E,f1,f2,bb,n);  
  268.                     H.Insert(N);  
  269.                 }  
  270.                 Swap(E.x[E.s],E.x[i]);  
  271.             }  
  272.             delete []E.x;//完成节点扩展   
  273.         }  
  274.         if(H.Size() == 0)  
  275.         {  
  276.             break;  
  277.         }  
  278.         H.DeleteMin(E);//取下一扩展节点   
  279.     }  
  280.     return bestc;  
  281. }  
  282.   
  283. template <class Type>  
  284. inline void Swap(Type &a, Type &b)  
  285. {   
  286.     Type temp=a;   
  287.     a=b;   
  288.     b=temp;  
  289. }  
//批作业调度问题 优先队列分支限界法求解 
#include "stdafx.h"
#include "MinHeap2.h"
#include <iostream>
using namespace std;

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<<"各作业所需要的时间处理数组M(i,j)值如下:"<<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<<"(";
		for(int j=0;j<2;j++)
		cout<<M[i][j]<<" ";
		cout<<")";
	}
	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;
}
     程序运行结果如图:



分支限界法(Branch and Bound)是一种用于求解离散优化问题算法,它在整数规划和搜索问题中特别有效,包括某些类型的作业调度问题。在作业调度中,假设每个作业有一个开始时间和结束时间,目标可能是找到一种最优的作业安排,使得完成所有作业的时间最短或者满足特定的资源约束。 对于批处理作业调度问题,其中涉及到多个任务或作业,每个任务有一个执行时间和优先级。分支限界法可以应用于以下场景: 1. **任务排序**:决定哪些任务应该首先执行,然后根据剩余的任务调整策略,比如采用最早开始时间(EDF, Earliest Deadline First)或最迟结束时间(LDF, Latest Finish Time)策略。 2. **资源分配**:如果有共享资源,如何分配这些资源以最大化效率或最小化截止日期违反。 3. **动态规划**:通过构建决策树,将问题分解为子问题,并利用上一阶段的结果来指导当前阶段的选择。 分支限界法的工作流程大致如下: - **节点生成**:从初始状态开始,生成所有可能的子状态(即可能的作业执行顺序)。 - **剪枝**:评估每个节点的上界(upper bound)或下界(lower bound),如果当前节点的目标值肯定超过最优解,就直接舍弃。 - **分支**:选择具有最大潜力提升的子节点进行深入。 - **回溯**:当达到某个节点没有更好的解决方案时,回溯到父节点并尝试其他分支。 - **递归终止条件**:当找到满足目标条件的解或者搜索树被完全探索后,算法停止。 **相关问题--:** 1. 作业调度问题中的具体优化目标是什么? 2. 在批处理作业调度中,如何定义节点的剪枝条件? 3. 分支限界法如何处理优先级变化或资源限制对任务顺序的影响?
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值