zoukankan      html  css  js  c++  java
  • POJ1180 Batch Scheduling 解题报告(斜率优化)

    题目链接:http://poj.org/problem?id=1180

    题目描述:

    There is a sequence of N jobs to be processed on one machine. The jobs are numbered from 1 to N, so that the sequence is 1,2,..., N. The sequence of jobs must be partitioned into one or more batches, where each batch consists of consecutive jobs in the sequence. The processing starts at time 0. The batches are handled one by one starting from the first batch as follows. If a batch b contains jobs with smaller numbers than batch c, then batch b is handled before batch c. The jobs in a batch are processed successively on the machine. Immediately after all the jobs in a batch are processed, the machine outputs the results of all the jobs in that batch. The output time of a job j is the time when the batch containing j finishes. 

    A setup time S is needed to set up the machine for each batch. For each job i, we know its cost factor Fi and the time Ti required to process it. If a batch contains the jobs x, x+1,... , x+k, and starts at time t, then the output time of every job in that batch is t + S + (Tx + Tx+1 + ... + Tx+k). Note that the machine outputs the results of all jobs in a batch at the same time. If the output time of job i is Oi, its cost is Oi * Fi. For example, assume that there are 5 jobs, the setup time S = 1, (T1, T2, T3, T4, T5) = (1, 3, 4, 2, 1), and (F1, F2, F3, F4, F5) = (3, 2, 3, 3, 4). If the jobs are partitioned into three batches {1, 2}, {3}, {4, 5}, then the output times (O1, O2, O3, O4, O5) = (5, 5, 10, 14, 14) and the costs of the jobs are (15, 10, 30, 42, 56), respectively. The total cost for a partitioning is the sum of the costs of all jobs. The total cost for the example partitioning above is 153. 

    You are to write a program which, given the batch setup time and a sequence of jobs with their processing times and cost factors, computes the minimum possible total cost. 

    Input

    Your program reads from standard input. The first line contains the number of jobs N, 1 <= N <= 10000. The second line contains the batch setup time S which is an integer, 0 <= S <= 50. The following N lines contain information about the jobs 1, 2,..., N in that order as follows. First on each of these lines is an integer Ti, 1 <= Ti <= 100, the processing time of the job. Following that, there is an integer Fi, 1 <= Fi <= 100, the cost factor of the job.

    Output

    Your program writes to standard output. The output contains one line, which contains one integer: the minimum possible total cost.

    Sample Input

    5
    1
    1 3
    3 2
    4 3
    2 3
    1 4

    Sample Output

    153

    Source

     
    看不懂题面的随便找一个翻译软件翻译一下效果都还是不错的,至少看得懂题
     
    下面直接解题:
    解法一:求出T,C的前缀和sumT和sumC,设f(i,j)表示把前i个任务分成j批去执行的最小费用,状态转移方程为
    f(i,j)=min(0<=k<i){f(k,j-1)+(s*j+sumT[i])*(sumC[i]-sumC[k])}
    时间复杂度为O(N3)
    解法二:
    本题其实没有规定把任务分成多少批,也就是说解法一其实有无用的状态
    现在我们设f(i)表示把前i个任务分成若干批处理的最小费用,状态转移方程为
    f[i]=min(0<=j<i){f[j]+sumT[i]*(sumC[i]-sumC[j])+s*(sumC[N]-sumC[j])}
    这种思想叫做“费用提前计算”,先把每次s的贡献直接加起来
    时间复杂度O(N2)
    解法三:
    我们考虑到这题的数据,对解法二的状态转移方程进行斜率优化。
    去掉min,通过移项我们可以得到f[j]=(s+sumT[i])*sumC[j]+f[i]-sumT[i]*sumC[i]-s*sumC[N]
    我们发现,在以sumC[j]为横坐标,f[j]为纵坐标的坐标系中,这是条以(s+sumT[i])为斜率,f[i]-sumT[i]*sumC[i]-s*sumC[N]为截距的直线
    由于-sumT[i]*sumC[i]-s*sumC[N]是一个常数,斜率也是一个固定的值,这是一个线性规划问题,我们每次取最小的截距
    对于点集(sumC[j],f[j])我们其实只需要维护一个下凸壳就行了。当我们需要找到当前的最优的点时,设k=s+sumT[i],最优的点和它左边的点的斜率比k小,和它右边的斜率比k大,参考下面的图。
     
    另外我们还发现一点,由于sumC具有单调性,每次加入的点都会在最右边。并且sumT同样具有单调性,这说明斜率是递增的。因此我们只需要维护比当前斜率大的一条条线段,可以通过一个单调队列q来实现
    具体操作如下:
    1.检查队头的两个决策变量q[l]和q[l+1],斜率f[q[l+1]]-f[q[l]]/(sumC[q[l+1]]-sumC[q[l]])<=s+sumT[i],则把q[l]出队,继续检查新的队头。
    2.直接取队头j=q[l]作为最优策略,执行状态转移,得到f[i]
    3.把新决策i从队尾插入,在插入之前,若三个决策点j1=q[r-1],j2=q[r],j3=i不满足斜率单调递增(不满足下凸性,即i是无用决策),则直接从队尾把q[r]出队,继续检查新的队尾。
    整个算法的时间复杂度O(N),完美的解决问题。
     
    下面附上代码:
    #include<bits/stdc++.h>
    #define ll long long
    using namespace std;
    
    const int maxn=1e4+15;
    int n,s;
    int sumt[maxn],sumc[maxn],q[maxn];
    ll f[maxn];
    int main()
    {
        scanf("%d%d",&n,&s);
        for (int i=1;i<=n;i++)
        {
            int t,c;
            scanf("%d%d",&t,&c);
            sumt[i]=sumt[i-1]+t;
            sumc[i]=sumc[i-1]+c;
        }
        int l=1,r=1;
        for (int i=1;i<=n;i++)
        {
            while (l<r&&(f[q[l+1]]-f[q[l]])<=(s+sumt[i])*(sumc[q[l+1]]-sumc[q[l]])) l++;
            f[i]=f[q[l]]-(s+sumt[i])*sumc[q[l]]+sumt[i]*sumc[i]+s*sumc[n];
            while (l<r&&(f[q[r]]-f[q[r-1]])*(sumc[i]-sumc[q[r]])>=(f[i]-f[q[r]])*(sumc[q[r]]-sumc[q[r-1]])) r--;
            q[++r]=i;
        }
        printf("%lld",f[n]);
        return 0;
    }

    声明:本博客内容参考李煜东算法竞赛进阶指南

  • 相关阅读:
    括号序列
    NOI剑客决斗
    洛谷 P1896 [SCOI2005]互不侵犯King
    codevs贪吃的九头龙
    ie6绝对定位的块会被select元素遮挡的解决方案
    Normalize.css与Reset CSS:定义浏览器统一的默认样式
    IE6中PNG图片背景无法透明显示的最佳解决方案
    关于ie6中绝对定位或浮动的div中既有向左float也有向右float时候如何让外层div自适应宽度的解决方案--
    [Z]关于html中的条件注释
    [z]IE6各种不兼容问题
  • 原文地址:https://www.cnblogs.com/xxzh/p/9254407.html
Copyright © 2011-2022 走看看