http://caioj.cn/problem.php?id=1084
题目描述
【问题描述】
N个任务排成一个序列在一台机器上等待完成(顺序不得改变),这N个任务被分成若干批,每批包含相邻的若干任务。从时刻0开始,这些任务被分批加工,第i个任务单独完成所需的时间是Ti。在每批任务开始前,机器需要启动时间S,而完成这批任务所需的时间是各个任务需要时间的总和(同一批任务将在同一时刻完成)。每个任务的费用是它的完成时刻乘以一个费用系数Fi。请确定一个分组方案,使得总费用最小。
例如:S=1;T={1,3,4,2,1};F={3,2,3,3,4}。如果分组方案是{1,2}、{3}、{4,5},则完成时间分别为{5,5,10,14,14},费用C={15,10,30,42,56},总费用就是153。
【输入文件】
第一行是n(1<=n<=5000);
第二行是s(0<=s<=50)。
下面n行每行有一对数,分别为Ti和Fi,均为不大于100的正整数,表示第i个任务单独完成所需的时间是Ti及其费用系数Fi。
【输出文件】
一个数,最小的总费用。
【输入输出样例】
输入:
5
1
1 3
3 2
4 3
2 3
1 4
输出:
153
错误解法:设f[i]表示前i个完成所需的最小花费,g[i]表示前i个取得最小花费时分的组数,则f[i]=min{f[j]+s*(g[j]+1)*t*p·}
因为方案有后效性,分不同的组对后面的花费有影响。
#include<bits/stdc++.h>
#define f(i,l,r) for(i=(l);i<=(r);i++)
#define ff(i,r,l) for(i=(r);i>=(l);i--)
using namespace std;
const int MAXN=5005,INF=1e9;
int n,S;
struct Edge{
int t,f;
}a[MAXN];
int f[MAXN];
int main()
{
ios::sync_with_stdio(false);
memset(f,60,sizeof(f));
int ans=INF;
int i,j,k;
cin>>n>>S;
f(i,1,n){
cin>>a[i].t>>a[i].f;
a[i].t+=a[i-1].t;
a[i].f+=a[i-1].f;
}
f[0]=0;
f(i,1,n){
f(j,0,i-1){
if(f[i]>f[j]+a[i].t*(a[i].f-a[j].f)+S*(a[n].f-a[j].f)){
f[i]=f[j]+a[i].t*(a[i].f-a[j].f)+S*(a[n].f-a[j].f);
}
}
}
cout<<f[n]<<endl;
return 0;
}
改进:增加一个维度来表示分成的组数,f[i][k]表示前i个分成k组。
#include<bits/stdc++.h>
#define f(i,l,r) for(i=(l);i<=(r);i++)
#define ff(i,r,l) for(i=(r);i>=(l);i--)
using namespace std;
const int MAXN=5005,INF=1e9;
int n,S;
struct Edge{
int t,f;
}a[MAXN];
int dp[MAXN][MAXN],f[MAXN];
int main()
{
ios::sync_with_stdio(false);
memset(dp,60,sizeof(dp));
int ans=INF;
int i,j,k;
cin>>n>>S;
f(i,1,n){
cin>>a[i].t>>a[i].f;
a[i].t+=a[i-1].t;
a[i].f+=a[i-1].f;
}
dp[0][0]=0;
f[0]=1;
f(i,1,n){
f(j,0,i-1){
f(k,1,j+1){
if(dp[i][k]>dp[j][k-1]+(k*S+a[i].t)*(a[i].f-a[j].f)){
dp[i][k]=dp[j][k-1]+(k*S+a[i].t)*(a[i].f-a[j].f);
}
}
}
}
// f(i,0,n) cout<<i<<": "<<dp[i]<<"GG"<<endl;
f(i,1,n) ans=min(ans,dp[n][i]);
cout<<ans<<endl;
return 0;
}
然而这样会超时,仍然需要优化。
增加一个维度就是为了处理后效性,其实可以在转移的时候就把后效性处理掉。每当一个计划开始时,开机需要s秒,相当于这个计划里的任务以及后面的任务都被损失了s秒,将这个时间损失转化为费用损失即可。
#include<bits/stdc++.h>
#define f(i,l,r) for(i=(l);i<=(r);i++)
#define ff(i,r,l) for(i=(r);i>=(l);i--)
using namespace std;
const int MAXN=5005,INF=1e9;
int n,S;
struct Edge{
int t,f;
}a[MAXN];
int f[MAXN];
int main()
{
ios::sync_with_stdio(false);
memset(f,60,sizeof(f));
int ans=INF;
int i,j,k;
cin>>n>>S;
f(i,1,n){
cin>>a[i].t>>a[i].f;
a[i].t+=a[i-1].t;
a[i].f+=a[i-1].f;
}
f[0]=0;
f(i,1,n){
f(j,0,i-1){
if(f[i]>f[j]+a[i].t*(a[i].f-a[j].f)+S*(a[n].f-a[j].f)){
f[i]=f[j]+a[i].t*(a[i].f-a[j].f)+S*(a[n].f-a[j].f);
}
}
}
cout<<f[n]<<endl;
return 0;
}