poj 1180 Batch Scheduling
http://poj.org/problem?id=1180
题意:N个任务排成一个序列在一台机器上等待完成(顺序不得改变),这N个任务被分成若干批,每批包含相邻的若干任务。 从时刻0开始,这些任务被分批加工,第i个任务单独完成所需的时间是Ti。在每批任务开始前,机器需要启动时间S,而完成这批任务所需的时间是各个任务需 要时间的总和(同一批任务将在同一时刻完成)。每个任务的费用是它的完成时刻乘以一个费用系数Fi。请确定一个分组方案,使得总费用最小。(1 <= N <= 10000)
朴素状态转移方程:dp[i][j]=MIN(dp[i-1][k]+(S*i+T[j])*(c[j]-c[k]) )
可从后像前推,得dp[i]= MIN(dp[j] + (s + t[i]- t[j])) *f[i]; ( i< j<= n+ 1)
贴个博客http://blog.csdn.net/ascii991/article/details/7545261像大牛学习~~
#include <iostream>
#include <cstdio>
#include <cstring>
using namespace std;
const int maxn= 10005;
long long dp[maxn];
int n, s, t[maxn], f[maxn], q[maxn];
void dynamic(){
int i, j, k, head, tail;
tail= 0;head= 0;
dp[n+1]= f[n+1]= t[n+1]= 0;
q[tail++]= n+1;
/*状态转移方程: dp[i]= MIN(dp[j] + (s + t[i]- t[j])) *f[i]; ( i< j<= n+ 1)
i <j <k时:(dp[j]- dp[k])/(t[j]- t[k]) >= f[i] 为 k不差于j的条件
g[j, k] >= f[i] k不差于j的条件
g[j, k] < f[i] j 优于 k
对于队首元素a > b,若g[b, a] <= f[i],则b不差于a
且f随i递减而递增,故对于以后的f[p],g[b, a]必定小于f[p],所以head++
对于队尾元素,a>b, 新加的i<b,即 a>b>i
若 g[i, b]< g[b, a] 时,b永远不会被选到
证明:g[i, b] >= f[i] ,i为不差于b
f[i]> g[b, a] > g[i, b]时,b优于a,但i优于b,故不选b
*/
for( i= n; i>= 1; i--){
while( tail - head >= 2 && (dp[q[head+1]] - dp[q[head]])
<= ( t[q[head+1]] - t[q[head]])*f[i])
head++;
dp[i]= dp[q[head]] + (s+ t[i] - t[q[head]])* f[i];
while( tail - head >= 2 && (dp[i] - dp[q[tail-1]])*(t[q[tail-1]] - t[q[tail-2]]) < (dp[q[tail-1]] - dp[q[tail-2]])*(t[i]- t[q[tail-1]]))
tail--;
q[tail++]= i;
}
printf("%I64d\n",dp[1]);
}
int main(){
// freopen("1.txt", "r", stdin);
int i, j, aa, bb;
while( scanf("%d%d", &n, &s)!= EOF){
t[0]= f[0]= 0;
for( i= 1; i<= n; i++){
scanf("%d%d", &aa, &bb);
t[i]= aa;
f[i]= bb;
}
t[n+1]= 0;
f[n+1]= 0;
for( i= n; i>= 1; i--){
t[i]+= t[i+1];
f[i]+= f[i+1];
}
dynamic();
}
return 0;
}