1606:【 例 1】任务安排 1
时间限制: 1000 ms 内存限制: 524288 KB
提交数: 203 通过数: 149
【题目描述】
有 N 个任务排成一个序列在一台机器上等待执行,它们的顺序不得改变。机器会把这 N 个任务分成若干批,每一批包含连续的若干个任务。从时刻 0 开始,任务被分批加工,执行第i个任务所需的时间是 Ti。另外,在每批任务开始前,机器需要 S 的启动时间,故执行一批任务所需的时间是启动时间 S 加上每个任务所需时间之和。
一个任务执行后,将在机器中稍作等待,直至该批任务全部执行完毕。也就是说,同一批任务将在同一时刻完成。每个任务的费用是它的完成时刻乘以一个费用系数 Ci 。
请为机器规划一个分组方案,使得总费用最小。
【输入】
第一行是 N。第二行是 S。
下面 N 行每行有一对正整数,分别为 Ti和 Ci ,表示第 i 个任务单独完成所需的时间是 Ti 及其费用系数 Ci 。
【输出】
一个数,最小的总费用。
【输入样例】
5
1
1 3
3 2
4 3
2 3
1 4
【输出样例】
153
【提示】
样例说明:
分组方案为{1,2},{3},{4,5},则完成时间为 {5,5,10,14,14},费用 C={15,10,30,42,56},总费用为 153。
数据范围与提示:
对于全部数据,1≤N≤5000,0≤S≤50,1≤Ti,Ci≤100。
思路:
先设置出一般的转移方程:
f[i][j]表示把前i个任务分成j批执行的最小费用
f[i][j]=min(f[k][j-1]+(sum[i]+sj)(c[i]-c[k]))
复杂度O(n^3)
考虑优化一下,这里介绍一个经典思想:费用提前计算
我们可以不直接求每批任务的完成时刻,而是在一批任务的开始对后续产生影响时,就把费用加进结果中
如果用上面的方法,那么转移方程就变成了:
f[i]表示把前i个任务分成若干批的最小费用
f[i]=min(f[j]+sum[i](c[i]-c[j])+s(c[n]-c[j]))
上面的式子表示我们先不考虑s的影响,求出最小费用,再加上s对于j后面的数的影响即可
代码:
#include<bits/stdc++.h>
#define ll long long
#define maxn 5020
using namespace std;
int f[maxn],a[maxn],c[maxn],suma[maxn],sumc[maxn];
int n,s;
int main()
{
cin>>n>>s;
for(int i=1;i<=n;i++) cin>>a[i]>>c[i];
for(int i=1;i<=n;i++)
{
suma[i]=suma[i-1]+a[i];
sumc[i]=sumc[i-1]+c[i];
}
memset(f,0x3f,sizeof(f));
f[0]=0;
for(int i=1;i<=n;i++)
{
for(int j=0;j<i;j++)
{
f[i]=min(f[i],f[j]+suma[i]*(sumc[i]-sumc[j])+s*(sumc[n]-sumc[j]));
}
}
cout<<f[n]<<'
';
return 0;
}