Poj1180 Batch Scheduling --- DP的斜率优化

题意

N个任务排成一个序列在一台机器上等待完成(顺序不得改变),这N个任务被分成若干批,每批包含相邻的若干任务。从时刻0开始,这些任务被分批加工,第i 个任务单独完成所需的时间是Ti。在每批任务开始前,机器需要启动时间S,而完成这批任务所需的时间是各个任务需要时间的总和(同一批任务将在同一时刻完 成)。每个任务的费用是它的完成时刻乘以一个费用系数Fi。请确定一个分组方案,使得总费用最小。

算法讨论

毫无疑问DP.转移方程:dp[i]=Min{dp[j]+(sumF[i]-sumF[j])*sumT[i]+s*(sumF[N]-sumF[j])},其中dp[i]表示的是完成1~i的工作的花费+因为开机启动时间所浪费的后面的花费。

但是这个转移方程的复杂度是O(N^2)的,如果RP好的话可以试试~但是显然,我们有更强大的方法:斜率优化。

至于什么是斜率优化……可以百度一下“斜率优化”……

只说说这道题的证明:

设G[i,j]表示dp[i]的决策为j时的dp[i]值。

设j1<j2,且G[i,j1]<G[i,j2](即以j1为决策时优于j2)

G[i,j1]=dp[j1]-sumF[j1]*sumT[i]-s*sumF[j1]+s*sumF[N]+sumF[i]*sumT[i]

G[i,j2]=dp[j2]-sumF[j2]*sumT[i]-s*sumF[j2]+s*sumF[N]+sumF[i]*sumT[i]

G[i,j1]-G[i,j2]=(dp[j1]-s*sumF[j1])-(dp[j2]-s*sumF[j2])-sumT[i]*(sumF[j1]-sumF[j2])<0

整理得

【(dp[j1]-s*sumF[j1])-(dp[j2]-s*sumF[j2])】

---------------------------------------------------------------------     > sumT[i]

    (sumF[j1]-sumF[j2])

又因为sumT[i]单调不降

所以最优决策单调

那么维护一个队列就可以了。

参考代码:

# include <iostream>

# include <cstdio>

# include <cmath>

using namespace std;

const int maxN=10005;

long long dp[maxN],f[maxN],t[maxN],N,s;

long long calc(int,int);

int slope(int,int,int);



int main()

{

	int seq[maxN],fi,ti,l=1,r=1;

	seq[1]=0;

	scanf("%lld",&N);scanf("%lld",&s);

	for (int i=1;i<=N;i++){

		scanf("%d%d",&ti,&fi);t[i]=t[i-1]+ti;f[i]=f[i-1]+fi;

	}

	for (int i=1;i<=N;i++){

		while ((l<r)&&(calc(i,seq[l])>calc(i,seq[l+1]))) l++;

		dp[i]=calc(i,seq[l]);

		while ((l<r)&&(slope(seq[r],seq[r-1],i))) r--;

		seq[++r]=i;

	}

	printf("%lld\n",dp[N]);

	return 0;

}



long long calc(int i,int j)

{

	return dp[j]+(f[i]-f[j])*t[i]+s*(f[N]-f[j]);

}



int slope(int i,int j,int k)

{

	long long imj=((dp[k]-s*f[k])-(dp[i]-s*f[i]))*(f[k]-f[j]);

	long long jmi=((dp[k]-s*f[k])-(dp[j]-s*f[j]))*(f[k]-f[i]);

	return imj<jmi;

}

 



你可能感兴趣的:(batch)