⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 余新华-5.5.txt

📁 这是很不错的计算机算法
💻 TXT
字号:
/*批处理作业调度问题求解程序*/
/*本程序运行前提:
  在源程序目录下存在input.txt文件,并且该文件已经按一定格式存储若干值
/*本程序在tc++3.0和vc++6.0上运行通过*/
#include<fstream.h>
#include<stdlib.h>
#include<iomanip.h>
#include<conio.h>

int size;//批处理作业个数 
class flowshop;//预先声明flowshop类 

/*交换函数的定义*/ 
void swap(int& a,int& b)
{
  int temp;
  temp=a;
  a=b;
  b=temp;
}

/*------------类minheapnode的定义开始(表示堆结点)-----------------*/ 
class minheapnode
{
  friend flowshop;//友元类 
  public:
    int bb;//当前完成时间和下界 
    minheapnode();//构造函数 
    minheapnode(minheapnode& temp);//拷贝构造函数 
    minheapnode& operator = (minheapnode& temp);//赋值运算符重载 
    ~minheapnode();//析构函数 
  private:
    int s;//已安排作业数 
    int f1;//机器1上最后完成时间 
    int f2;//机器2上最后完成时间 
    int sf2;//当前机器2上的完成时间和 
    int *x;//当前作业调度 
    void newnode(minheapnode,int,int,int,int);//对象赋值函数 
};

/*构造函数的定义*/ 
minheapnode::minheapnode()
{
  x=new int[size];//分配x数组 
  for(int i=0;i<size;i++) x[i]=i;//x数组初始化 
  s=f1=f2=sf2=bb=0;//其他成员初始化 
}

/*拷贝构造函数的定义*/ 
minheapnode::minheapnode(minheapnode& temp)
{
  s=temp.s;
  f1=temp.f1;
  f2=temp.f2;
  sf2=temp.sf2;
  bb=temp.bb;//各个成员赋值拷贝 
  x=new int[size];//分配x数组 
  for(int i=0;i<size;i++) x[i]=temp.x[i];//拷贝x数组 
}

/*赋值运算符重载函数的定义*/ 
minheapnode& minheapnode::operator = (minheapnode& temp)
{
  s=temp.s;
  f1=temp.f1;
  f2=temp.f2;
  sf2=temp.sf2;
  bb=temp.bb;//各个成员赋值 
  for(int i=0;i<size;i++) x[i]=temp.x[i];//x数组赋值 
  return *this;//返回对象 
}

/*析构函数的定义*/ 
minheapnode::~minheapnode()
{
  delete[] x;//释放x数组所占内存 
}

/*对象赋值函数的定义*/ 
void minheapnode::newnode(minheapnode e,int ef1,int ef2,int ebb,int n)
{
  x=new int[n];//分配x数组 
  for(int i=0;i<n;i++) x[i]=e.x[i];//x数组赋值 
  f1=ef1;
  f2=ef2;
  sf2=e.sf2+f2;
  bb=ebb;
  s=e.s+1;//其他成员赋值 
}
/*------------类minheapnode的定义结束-----------------*/


/*------------类minheap的定义开始(表示最小堆)-----------------*/
class minheap
{
  private:
    minheapnode *heap;//堆数组 
    int currentsize;//当前堆元素个数 
    int heapsize;//堆大小 
    void filterdown(int start,int endofheap);//向下调整 
    void filterup(int start);//向上调整 
  public:
    minheap(int n);//构造函数 
    ~minheap();//析构函数 
    int insert(minheapnode& x);//插入函数 
    int removemin(minheapnode& x);//删除最小值函数 
    int isempty();//判断空函数 
    int isfull();//判断满函数 
    void makeempty();//置空函数 
};

/*构造函数的定义*/ 
minheap::minheap(int n)
{
  heapsize=n;//设置堆大小 
  currentsize=0;//设置0表示堆中无结点 
  if(!(heap=new minheapnode[heapsize]))//分配heap数组
  {
    cerr<<"insufficient memory!"<<endl;//分配不成功,退出
    exit(-1);
  }
}

/*析构函数的定义*/ 
minheap::~minheap()
{
  delete[] heap;//释放heap数组所占内存 
}

/*判断空函数的定义*/ 
int minheap::isempty()
{
  return currentsize==0;
}

/*判断满函数的定义*/ 
int minheap::isfull()
{
  return currentsize==heapsize;
}

/*置空函数的定义*/ 
void minheap::makeempty()
{
  currentsize=0;//设定0表示堆中无结点 
}

/*向下调整函数的定义*/ 
void minheap::filterdown(int start,int endofheap)
{
  int i=start,j=2*i+1;//j是i的左子女 
  minheapnode temp=heap[i];//预先保存i位置的值 
  while(j<=endofheap)
  {
    if(j<endofheap&&heap[j].bb>heap[j+1].bb) j++;//选出两子女中更小值位置 
    if(temp.bb<=heap[j].bb) break;//如果比最小值更小则不需调整 
    else 
    {
      heap[i]=heap[j];//将最小值移动到根位置 
      i=j;//设置新的根位置 
      j=2*j+1;//新的左子女位置,继续向下调整 
    }
  }
  heap[i]=temp;//将初始位置的结点移动到新位置 
}

/*向上调整函数的定义*/ 
void minheap::filterup(int start)
{
  int j=start,i=(j-1)/2;//j是i的双亲 
  minheapnode temp=heap[j];//预先保存j位置的值 
  while(j>0)
  {
    if(heap[i].bb<temp.bb) break;//如果双亲更小则不需调整 
    else
    {
      heap[j]=heap[i];//将最小值移动到双亲位置上 
      j=i;//设置新的子女位置 
      i=(i-1)/2;//新的双亲位置,继续向上调整 
    }
  }
  heap[j]=temp;//将初始位置的结点移动到新位置 
}

/*插入函数的定义*/ 
int minheap::insert(minheapnode& x)
{
  if(currentsize==heapsize)//堆已满不能插入 
  {
    cout<<"堆已满"<<endl;
    return 0;
  }	
  heap[currentsize]=x;//在堆尾插入元素 
  filterup(currentsize);//向上调整为最小堆 
  currentsize++;//元素个数加1 
  return 1;
}

/*删除最小值函数的定义*/ 
int minheap::removemin(minheapnode& x)
{
  if(!currentsize)//堆空不能删除 
  { 
    cout<<"堆已空"<<endl;
    return 0; 
  }
  x=heap[0];//堆首元素赋给x 
  heap[0]=heap[currentsize-1];//堆尾元素移动到堆首	    
  currentsize--;//元素个数减1 
  filterdown(0,currentsize-1);//向下调整为最小堆 
  return 1;
}
/*------------类minheap的定义结束-----------------*/


/*------------类flowshop的定义开始(表示调度类)----------------*/ 
class flowshop
{
  public:
    void bbflow();//优先队列式分支限界法求解 
    flowshop();//构造函数 
    ~flowshop();//析构函数 
    void outputtofile();//输出解信息 
  private:
    int bound(minheapnode,int&,int&,int**);//计算完成时间和下界 
    void sort();//排序 
    int n;//批处理作业个数 
    int **m;//个作业所需的处理时间数组 
    int **b;//个作业所需的处理时间排序后数组 
    int **a;//数组m和b的对应关系数组(a[i][j]=k表示编号为i的作业在数组b中的位置是k,即第k个处理) 
    int *bestx;//最优解 
    int bestc;//最小完成时间和 
    int **y;//y[i][j]表示作业i在机器j上是否已完成 
};

/*构造函数的定义*/ 
flowshop::flowshop()
{
  int i,j;//循环控制变量 
  ifstream fin("input.txt",ios::nocreate);//打开输入文件
  fin>>n;//读入作业个数 
  size=n;//设置size值 
  if(!(m=new int*[n]))//分配二维数组m 
  {
    cerr<<"insufficient memory!"<<endl;//分配不成功,退出
    exit(-1);
  }
  for(i=0;i<n;i++)
    if(!(m[i]=new int[2]))//为每个一维数组分配空间
    {
      cerr<<"insufficient memory!"<<endl;//分配不成功,退出
      delete[] m;
      exit(-1);
    }
  if(!(b=new int*[n]))//分配二维数组b 
  {
    cerr<<"insufficient memory!"<<endl;//分配不成功,退出
    exit(-1);
  }
  for(i=0;i<n;i++)
    if(!(b[i]=new int[2]))//为每个一维数组分配空间
    {
      cerr<<"insufficient memory!"<<endl;//分配不成功,退出
      delete[] b;
      exit(-1);
    }
  if(!(a=new int*[n]))//分配二维数组a 
  {
    cerr<<"insufficient memory!"<<endl;//分配不成功,退出
    exit(-1);
  }
  for(i=0;i<n;i++)
    if(!(a[i]=new int[2]))//为每个一维数组分配空间
    {
      cerr<<"insufficient memory!"<<endl;//分配不成功,退出
      delete[] a;
      exit(-1);
    }
  if(!(y=new int*[n]))//分配二维数组y 
  {
    cerr<<"insufficient memory!"<<endl;//分配不成功,退出
    exit(-1);
  }
  for(i=0;i<n;i++)
    if(!(y[i]=new int[2]))//为每个一维数组分配空间
    {
      cerr<<"insufficient memory!"<<endl;//分配不成功,退出
      delete[] y;
      exit(-1);
    }
  if(!(bestx=new int[n]))//分配bestx数组
  {
    cerr<<"insufficient memory!"<<endl;//分配不成功,退出
    exit(-1);
  }
  for(i=0;i<n;i++)
    for(j=0;j<2;j++)
      fin>>m[i][j];//读入各个作业处理时间 
  fin.close();//关闭输入文件 
  bestc=100000;//设定bestc初始值 
}

/*析构函数*/ 
flowshop::~flowshop()
{
  int i;//循环控制变量 
  delete[] bestx;//释放bestx所占内存 
  for(i=0;i<n;i++)//释放二维m数组所占内存 
    delete[] m[i];
  delete[] m;
  for(i=0;i<n;i++)//释放二维b数组所占内存 
    delete[] b[i];
  delete[] b;
  for(i=0;i<n;i++)//释放二维a数组所占内存 
    delete[] a[i];
  delete[] a;
  for(i=0;i<n;i++)//释放二维y数组所占内存 
    delete[] y[i];
  delete[] y;
}

/*输出函数的定义*/      
void flowshop::outputtofile()
{
  ofstream out("output.txt");//创建输出文件
  out<<bestc<<endl;//输出最小完成时间和 
  for(int i=0;i<n;i++)
  {
    out<<bestx[i]+1<<" ";//输出最优解信息 
  }
  out.close();//关闭输出文件 
}     

/*排序函数的定义*/      
void flowshop::sort()//按照在机器1和机器2上的完成时间进行递增排序 
{
  int i,j,k;//循环控制变量 
  int *c;
  if(!(c=new int[n]))//分配c数组
  {
    cerr<<"insufficient memory!"<<endl;//分配不成功,退出
    exit(-1);
  }
  for(j=0;j<2;j++)//b和c数组初始化 
  {
    for(i=0;i<n;i++)
    {
      b[i][j]=m[i][j];
      c[i]=i;
    }
    for(i=0;i<n-1;i++)//冒泡排序趟数 
      for(k=n-1;k>i;k--)
        if(b[k][j]<b[k-1][j])
        {
          swap(b[k][j],b[k-1][j]);//交换b两元素 
          swap(c[k],c[k-1]);//同时交换c 
        }
    for(i=0;i<n;i++) a[c[i]][j]=i;//设置m和b的关系数组a 
  }
  delete[] c;//释放c所占内存 
}

//计算下界函数的定义*/ 
int flowshop::bound(minheapnode e,int& f1,int& f2,int **y)
{
  int j,k;//循环控制变量 
  for(k=0;k<n;k++)//y数组初始化 
    for(j=0;j<2;j++)
      y[k][j]=0;
  for(k=0;k<=e.s;k++)//设置已完成的作业标志为1 
    for(j=0;j<2;j++)
      y[a[e.x[k]][j]][j]=1;
  f1=e.f1+m[e.x[e.s]][0];//当前作业完成后机器1最后完成时间 
  f2=((f1>e.f2)?f1:e.f2)+m[e.x[e.s]][1];//当前作业完成后机器2最后完成时间 
  int sf2=e.sf2+f2;//当前作业完成后的完成时间和 
  int s1=0,s2=0,k1=n-e.s,k2=n-e.s,f3=f2;//初始化各变量 
  for(j=0;j<n;j++)//计算s1的值(机器1没有空闲的下界) 
    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];//累加每次作业的完成时间 
    }
  for(j=0;j<n;j++)//计算s2的值(机器2没有空闲的下界) 
    if(!y[j][1])
    {
      k2--;
      s1+=b[j][1];//s1的值 
      s2+=f3+k2*b[j][1];//累加每次作业的完成时间 
    }
  return sf2+((s1>s2)?s1:s2);//返回完成时间和下界 
}

void flowshop::bbflow()
{
  int i;//循环控制变量 
  sort();//对各作业在每机器上的完成时间进行排序 
  minheap h(100000);//创建大小为100000的堆 
  minheapnode e;//创建堆结点对象 
  while(e.s<=n)
  {
    if(e.s==n)//已到叶结点结束 
    {  
      if(e.sf2<bestc)//比当前最优值更小则更新 
      {
        bestc=e.sf2;//更新最优值 
        for(i=0;i<n;i++)//设置最优解 
          bestx[i]=e.x[i];
      }
    }
    else//否则继续扩展结点 
    {
      for(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]);//还原为原来的排列 
      }
    }
    if(!h.removemin(e)) break;//堆不为空,取下一扩展结点,否则退出循环 
  }
}
/*------------类flowshop的定义结束----------------*/ 


   
//主程序 
void main()
{
  flowshop flow;//创建flowshop对象 
  flow.bbflow();//进行调度求最优解 
  flow.outputtofile();//输出最优解 
}
  
/*排序对求解s1和s2的作用:
  如果不排序,则对于不同的调度情况s1和s2的值是不同的
  排序后,t从小到大排列,则对于(n-k+1)*t(k从r+1到n)这个和来说,越大的数乘的系数
  越小,保证了求得的s1和s2在剩余未执行的作业排列中是最小情况*/

⌨️ 快捷键说明

复制代码 Ctrl + C
搜索代码 Ctrl + F
全屏模式 F11
切换主题 Ctrl + Shift + D
显示快捷键 ?
增大字号 Ctrl + =
减小字号 Ctrl + -