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

Posted liylho

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了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 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

题意:N个任务排成一个序列在一台机器上等待接连完成,这N个任务被分成若干批相邻任务。 第i个任务单独完成所需的时间是Ti。在每批任务开始前,机器需要启动时间S,而完成这批任务所需的时间是各个任务需要时间的总和(同一批任务将在同一时刻完成)。每个任务的费用是它的所用时间乘以一个费用系数Fi。请确定一个分组方案,使得总费用最小。(1 <= N <= 10000)
思路:sumT[i]表示从i到n的任务所需要的时间总和,sumF[i]表示从i到n的费用系数总和,dp[i]表示对于从i到n的任务安排的最优解:

      dp[i]=min(dp[j]+(sunT[i]-sumT[j]+s)*sumF[i]) (1<=i<=n+1;i<j<=n+1)

我们考虑在计算dp[i]时,对于i < j < k来说, 如果保证决策k比决策j大的条件是:dp[j] + (S + sumT[i] - sumT[j]) * sumF[i] < dp[k] + (S + sumT[i] -sumT[k]) * sumF[i]

通过移项整理,可以化简为:(dp[j] - dp[k]) / (sumT[j] - sumT[k]) < sumF[i]

可知当我们计算dp[i]时,若(dp[j] - dp[k]) / (sumT[j] - sumT[k]) >=sumF[i]时我们可以舍弃j(决策K优于决策J);

因此我们可以用一个单调队列,对于元素i需要入对时,(i<j<k),我们如何维护呢,不妨设函数Q(j,k)=(dp[j] - dp[k]) / (sumT[j] - sumT[k]);

因为i需要入对,我们需要讨论的即是对于决策j,我们是否需要保留,(下面我们来讨论J需要舍弃的条件);

如果j需要舍弃,即对于决策i,j,i优于j;对于决策j,k,k优于j;故此我们有Q(i,j)<sumF[i],sumF[i]<=Q(j,k);  即推出 Qi,j)<Q(j,k);

综上:可以考虑维护一个斜率的队列来优化整个DP过程:

(1)假设i(马上要入队的元素)<j< k依次是队列尾部的元素,那么我们就要考虑Q(i,j)是否大于Q(j,k),如果Q(i,j) < Q(j,k),那么可以肯定j一定不会是决策点,可以从队列中将j去掉,依次向前推,直到找到一个队列元素少于2个或者Q(i,j)>= Q(j,k)的点才停止。

(2)假设k>j(k是头元素)是依次是队列头部的元素,如果g(j,k) < sumF[i]的话,那么对于i来说决策点j肯定优于决策点k,又由于sumF[i]是随着i减少而递增的,

所以当Q(j,k) < sumF[i]时,就一定有Q(j,k) < sumF[i-1],因此当前的决策点k不仅仅在考虑dp[i]时不会是最佳决策点,而且在后面的DP中也一定不会是最佳决策点,所以我们可以把k从队列 的头部删除,依次往后如此操作,直到队列元素小于2或者Q(j,k)>= sumF[i]。

代码:

 1 #include<sstream>
 2 #include<iomanip>
 3 #include"cstdio"
 4 #include"map"
 5 #include"set"
 6 #include"cmath"
 7 #include"queue"
 8 #include"vector"
 9 #include"string"
10 #include"cstring"
11 #include"time.h"
12 #include"iostream"
13 #include"stdlib.h"
14 #include"algorithm"
15 #define db double
16 #define ll long long
17 #define vec vectr<ll>
18 #define mt  vectr<vec>
19 #define ci(x) scanf("%d",&x)
20 #define cd(x) scanf("%lf",&x)
21 #define cl(x) scanf("%lld",&x)
22 #define pi(x) printf("%d\n",x)
23 #define pd(x) printf("%f\n",x)
24 #define pl(x) printf("%lld\n",x)
25 //#define rep(i, x, y) for(int i=x;i<=y;i++)
26 #define rep(i, n) for(int i=0;i<n;i++)
27 const int N   = 1e4+ 5;
28 const int mod = 1e9 + 7;
29 const int MOD = mod - 1;
30 const int inf = 0x3f3f3f3f;
31 const db  PI  = acos(-1.0);
32 const db  eps = 1e-10;
33 using namespace std;
34 ll dp[N];
35 int st[N],sf[N],deq[N];
36 int t[N],f[N];
37 int n,s;
38 db cal(int x,int y){
39     return db(dp[x]-dp[y])/db(st[x]-st[y]);
40 }
41 int main()
42 {
43     ci(n),ci(s);
44     for(int i=1;i<=n;i++) ci(t[i]),ci(f[i]);
45     for(int i=n;i;i--) st[i]=st[i+1]+t[i],sf[i]=sf[i+1]+f[i];
46     int l=1,r=0;
47     dp[n]=(s+st[n])*sf[n];
48     deq[++r]=n;
49     for(int i=n-1;i;i--)
50     {
51         while(r-l>=1 && cal(deq[l],deq[l+1])<sf[i]) l++;
52         int tt=s+st[i];
53         tt*=sf[i];
54         dp[i]=tt;
55         int j=deq[l];
56         tt=s+st[i]-st[j];
57         tt*=sf[i];
58         dp[i]=min(dp[i],dp[j]+tt);
59         while(r-l>=1 && cal(deq[r-1],deq[r])>cal(deq[r],i)) r--;
60         deq[++r]=i;
61     }
62     pl(dp[1]);
63     return 0;
64 }

 

以上是关于POJ 1180 斜率优化DP(单调队列)的主要内容,如果未能解决你的问题,请参考以下文章

斜率优化

斜率优化第一题! HDU3507 | 单调队列优化DP

HDU 3507 单调队列 斜率优化

DP单调队列--斜率优化P3195

斜率优化

POJ2373 Dividing the Path(单调队列优化dp)