带时限的作业排序

/*用贪心法求解作业排序问题。设有一个单机系统、无其他资源限制并且每个作业运行时间相等
,不妨设每个作业运行1个单位时间。现有n个作业,每个作业都有一个截止时间di>0。如果作业
能够在截止时间内完成,即可获得pi>0的收益。问题要求得到一种作业调度的方案,该方案给出
作业的一个子集和该作业子集的一种排列,使得按照这种排列次序调度作业运行,该子集中的每个
作业都能够如期完成,并且能够获得最大收益。也就是说,这种作业调度是最优的。*/
//一种一般方法:
/*具体做法是:将作业i按时限的非递减次序插入向量(x[0],x[1]...x[k])中得某个位置,舍得插入
作业i后,由k+1个分量组成的部分解向量仍按照时限的非递减次序排列。不妨设作业i被插入
于下标r+1处。为了在位置r+1处添加作业i,作业想x[r+1],...,x[k]在向量中的位置都必须依次
后移一位,形成一个新的部分解向量。为了保证在添加作业i后的作业子集仍然构成可行解,必须
满足下列两个条件:
1:d[x[i]]>i+1,r+1<=j<=k,否则作业x[r+1],...,x[k]的后移将导致其中某些作业超期;
2:d[j]>r+1,否则作业j自己无法在时刻r+2前完成。*/
int JS(int *d,int *x,int n)//d代表着截止时间,x代表所选作业的执行顺序,
                          //n代表作业的总数(并只不是选中的)
{//该作业已经按收益的非递减次序排序了
    int k=0;
    x[0]=0;
    for(int i=1;i     {
        int r=k;
        while(r>=0&&d[x[r]]>d[i]&&d[x[r]]>r+1)r--;
        if((r<0||d[x[r]]<=d[i])&&d[i]>r+1)
        {
            for(int j=k;j>r;j--)x[j+1]=x[j];
            x[r+1]=i;k++;
        }
    }
    return k;
}
//一种改进方法:
/*具体做法是:为收益最大的作业0分配时间片[d0-1,d0],为收益次大的作业1分配作业的时候
首先考虑时间片段[d1-1,d1],如果该时间片已分配,再考虑前一个时间片[d1-2,d1-1],依次
向前寻找第一个空闲的时间片分配之。如果d1之前的所有时间片均已分配,则作业1应该舍弃。
总之,这种方法采取的作业调度原则是尽可能推迟一个作业的执行时间。*/
/*
int Find(int i)
前置条件:i属于V,V是树中结点编号的集合
后置条件:返回包含结点i所在的树根编号
void Union(int x,int y)
前置条件:x和y为两棵树根的编号,并且x!=y
后置条件:合并x和y两棵树为一棵树
*/


int FJS(int *d,int *x,int n)//d代表着截止时间,x代表所选作业的执行顺序,
                          //n代表作业的总数(并只不是选中的)
{
    UFSet s(n);
    int b,k=-1,*f=new int [n+1];
    for(int i=0;i<=n;i++)f[i]=i;
    for(int i=0;i     {
        if(n         else b=d[i];
        int r=s.Find(b);
        if(f[r])
        {
            x[++k]=i;
            int t=s.find(f[r]-1);
            s.Union(t,r);
            f[r]=f[t];
        }
    }
    delete [] f;
    return k;
}

你可能感兴趣的:(学习笔记)