poj 1180 Batch Scheduling(DP-单调性优化)

Batch Scheduling

Time Limit: 1000MS   Memory Limit: 10000K
Total Submissions: 3145   Accepted: 1442

Description

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

题意:N个任务(按顺序编号1——N),1台机器。告诉你完成每个任务需要的时间Ti和完成每个任务的花费有关因素Fi。要你把这些任务分n(任意)批完成(同一批必须是相邻的),同一批任务完成的时间点相同。开始每一批任务之前需要启动机器,时间为S。每个任务的花费是完成的时间点t*Fi。
例如:
ID   1   2   3   4
T = {1 , 2 , 3 , 4};
F = {5 , 6 , 7 , 8};
S = 1;
把任务分成{1,2}、{3}、{4};
第一批完成花费:(S+T1+T2)*(F1+F2) = (1+1+2)*(5+6) = 44;
第二批完成花费:(S+T1+T2+S+T3)*F3 = (1+1+2+1+3)*7 = 56;
第三批完成花费:(S+T1+T2+S+T3+S+T4)*F4 = (1+1+2+1+3+1+4)*8 = 104;
总花费:44+56+104 = 204.
求最少花费。

思路:
DP[i] 表示第i-n个任务的最少花费。
DP[i] = min(DP[j]+(S+sumT[i]-sumT[j])*sumF[i]),
其中sumT[i]=sum{Ti+...Tn},sumF=sum{Fi+...Fn},j>i.

那么,我们正常的做法是枚举i(从n->1),然后枚举j,求出最小的,即:
for(int i = n; i >= 1; i--){
    for(int j = i+1; j <= n+1; j++){
        dp[i] = min(dp[i] , dp[j]+(S+sumT[i]-sumT[j])*sumF[i]);
    }
}
dp[n+1]=0.
这样效率是n*n,超时!
假设现在我要找i+1~n中的min(dp[j]+(S+sumT[i]-sumT[j])*sumF[i])),

若dp[j]+(S+sumT[i]-sumT[j])*sumF[i]) >= dp[k]+(S+sumT[i]-sumT[k])*sumF[i])则我们取k.

=>dp[j]-dp[k] >= (sumT[j]-sumT[k])*sumF[i];

=>分类讨论:

当 j>k:  (dp[j]-dp[k])/(sumT[j]-sumT[k]) <= sumF[i];(1)
当 j<k:  (dp[j]-dp[k])/(sumT[j]-sumT[k]) >= sumF[i];(2)

因此,如果我们找到的最小值是取k,则j>k的必定满足(1),j<k的必定满足(2)。

那么,当我们要找i~n时,当j>k必定满足(dp[j]-dp[k])/(sumT[j]-sumT[k]) <= sumF[i] <= sumF[i-1]
所以,我们就不用再去遍历j>k的那些数了!
int k = n+1;
for(int i = n; i >= 1; i--){
    int t = k;
    for(int j = i+1; j < k; j++){
        if(dp[j]+(S+sumT[i]-sumT[j])*sumF[i]) < dp[t]+(S+sumT[i]-sumT[t])*sumF[i])){
            t = j;
        }
    }
    k = t;
    dp[i] = dp[t]+(S+sumT[i]-sumT[t])*sumF[i]);
} 

#include <iostream>
#include <cstdio>
#include <vector>
using namespace std;

const int maxn = 10010;
int sumT[maxn] , sumF[maxn] , dp[maxn] , S , n;

void initial(){
    for(int i = 0; i < maxn; i++){
        sumT[i] = 0;
        sumF[i] = 0;
        dp[i] = 0;
    }
}

void readcase(){
    scanf("%d" , &S);
    for(int i = 0; i < n; i++){
        scanf("%d%d" , &sumT[i] , &sumF[i]);
    }
}

void computing(){
    for(int i = n-1; i >= 0; i--){
        sumT[i] += sumT[i+1];
        sumF[i] += sumF[i+1];
    }
    int k = n;
    for(int i = n-1; i >= 0; i--){
        int t = k;
        for(int j = i+1; j < k; j++){
            if(dp[j]+(S+sumT[i]-sumT[j])*sumF[i] < dp[t]+(S+sumT[i]-sumT[t])*sumF[i]){
                t = j;
            }
        }
        k = t;
        dp[i] = dp[t]+(S+sumT[i]-sumT[t])*sumF[i];
    }
    printf("%d\n" , dp[0]);
}

int main(){
    while(scanf("%d" , &n) != EOF){
        initial();
        readcase();
        computing();
    }
    return 0;
}

poj 1180 Batch Scheduling(DP-单调性优化),布布扣,bubuko.com

时间: 2024-10-05 16:46:07

poj 1180 Batch Scheduling(DP-单调性优化)的相关文章

[POJ 1180] Batch Scheduling

[题目链接] http://poj.org/problem?id=1180 [算法] 首先 , 用fi表示前i个任务花费的最小代价 有状态转移方程 : fi = min{ fj + sumTi(sumCi - sumCj) + S(sumCn - sunCj)} 直接进行转移的时间复杂度为O(N ^ 2) 对该式进行展开后不难看出 , 由于式子中有一些i和j的乘积项 , 所以可以进行斜率优化 推导过程略 时间复杂度 : O(N) [代码] #include<iostream> #include

dp单调性优化

跟着书上的思路学习dp的单调性优化觉得还是很容易想的. 数据范围: dp,数据范围是百万,这应该是O(n)的算法了. 首先不难想到设f[i]表示到第i个百米所能达到的最大能量,那么f[n]即为所求. f[i]=max(f[i],f[j]+s[i]-s[j]-cost[i]);这个地方s数组是能量的前缀和,然后发现需要多加一层循环来枚举j,这个时候就是O(n^2)的算法了. 这样的话,就只有40分了,毕竟看分做题.这分给的还是很良心的. 考虑优化首先我们发现状态转移方程可以这样变f[i]=max{

dp 单调性优化总结

对于单调性优化其实更多的是观察dp的状态转移式子的单调性 进而用优先队列 单调队列 二分查找什么的找到最优决策 使时间更优. 对于这道题就是单调性优化的很好的例子 首先打一个暴力再说. f[i][j]表示前i个木匠刷前j个木板所得到的最大价值 f[i][j]=max(f[i][j],f[i-1][j]); f[i][j]=max(f[i][j],f[i][j-1]) f[i][j]=max(f[i][j],f[i-1][k]+(j-k)*r(j));(k<t(j)<=j)&&(

poj 3709 K-Anonymous Sequence dp斜率优化

题意: 给长度为n的非严格递增数列a0,a1...an-1,每一次操作可以使数列中的任何一项的值减小1.现在要使数列中每一项都满足其他项中至少有k-1项和它相等.求最少操作次数. 分析: dp[i]:=只考虑前i项情况下,满足要求的最小操作次数. s[i]:=a0+a1+...+ai,则dp[i]=min(dp[j]+s[i]-s[j]-aj*(i-j))(0<=j<=i-k),可以看做dp[i]是这i-k+1条直线在x=i出的最小值,从而进行斜率优化. 代码: //poj 3709 //se

POJ 1160 (区间DP+四边形优化)

这个转移方程不好想,尤其是一段值的解是中间,不明觉厉.dp[i][j] 用i个邮局,覆盖前j个村庄的最小值. 还有就是区间dp的平行四边形优化,这个题的转移方程并不是"区间DP",所以枚举状态要逆着(很花时间),且用一个邮局覆盖都是从0断开了相当于没有断开. 类比于石子归并,矩阵链乘等标准区间DP,其所需状态之前就已经获得,不用倒推 #include <cstdio> #include <cstring> #include <iostream> us

POJ 1180 斜率优化DP(单调队列)

Batch Scheduling Time Limit: 1000MS   Memory Limit: 10000K Total Submissions: 4347   Accepted: 1992 Description 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 s

任务调度分配题两道 POJ 1973 POJ 1180(斜率优化复习)

POJ 1973 这道题以前做过的.今儿重做一次.由于每个程序员要么做A,要么做B,可以联想到0/1背包(谢谢N巨).这样,可以设状态 dp[i][j]为i个程序员做j个A项目同时,最多可做多少个B项目.枚举最后一个程序员做多少个A项目进行转移(0/1). dp[i][j]=max{dp[i-1][k]+(time-(j-k)*a[i])/b[i]}.于是,二分时间time进行判定即可. #include <iostream> #include <cstdio> #include

每日一dp(1)——Largest Rectangle in a Histogram(poj 2559)使用单调队列优化

Largest Rectangle in a Histogram 题目大意: 有数个宽为1,长不定的连续方格,求构成的矩形中最大面积 /************************************************************************/ /* 思路1. 当前为n的面积如何与n-1相联系,dp[i][j]=max(dp[i-1][k]) , 0<k<=j 描述:i为方块个数,j为高度 但是此题目的数据对于高度太变态,h,1000000000 ,n,1

POJ 1160 Post Office (四边形不等式优化DP)

题意: 给出m个村庄及其距离,给出n个邮局,要求怎么建n个邮局使代价最小. 析:一般的状态方程很容易写出,dp[i][j] = min{dp[i-1][k] + w[k+1][j]},表示前 j 个村庄用 k 个邮局距离最小,w可以先预处理出来O(n^2),但是这个方程很明显是O(n^3),但是因为是POJ,应该能暴过去..= =,正解应该是对DP进行优化,很容易看出来,w是满足四边形不等式的,也可以推出来 s 是单调的,可以进行优化. 代码如下: #pragma comment(linker,