POJ 1180 斜率优化DP(单调队列)
Posted liylho
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了POJ 1180 斜率优化DP(单调队列)相关的知识,希望对你有一定的参考价值。
Time Limit: 1000MS | Memory Limit: 10000K | |
Total Submissions: 4347 | Accepted: 1992 |
Description
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
Output
Sample Input
5 1 1 3 3 2 4 3 2 3 1 4
Sample Output
153
Source
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(单调队列)的主要内容,如果未能解决你的问题,请参考以下文章