HNOI2001 产品加工
[HNOI2001] 产品加工
题目描述
某加工厂有 A、B 两台机器,来加工的产品可以由其中任何一台机器完成,或者两台机器共同完成。由于受到机器性能和产品特性的限制,不同的机器加工同一产品所需的时间会不同,若同时由两台机器共同进行加工,所完成任务又会不同。
某一天,加工厂接到 \(n\) 个产品加工的任务,每个任务的工作量不尽一样。
你的任务就是:已知每个任务在 A 机器上加工所需的时间 \(t_1\),B 机器上加工所需的时间 \(t_2\) 及由两台机器共同加工所需的时间 \(t_3\),请你合理安排任务的调度顺序,使完成所有 \(n\) 个任务的总时间最少。
输入格式
第一行为一个整数 \(n\)。
接下来 \(n\) 行,每行三个非负整数 \(t_1,t_2,t_3\),分别表示第 \(i\) 个任务在 A 机器上加工、B 机器上加工、两台机器共同加工所需要的时间。如果所给的时间 \(t_1\) 或 \(t_2\) 为 \(0\) 表示任务不能在该台机器上加工,如果 \(t_3\) 为 \(0\) 表示任务不能同时由两台机器加工。
输出格式
仅一行一个整数,表示完成所有 \(n\) 个任务的最少总时间。
样例 #1
样例输入 #1
5
2 1 0
0 5 0
2 4 1
0 0 3
2 1 1
样例输出 #1
9
提示
对于所有数据,有 \(1\le n\le 6\times 10^3\), \(0\le t_1,t_2,t_3\le 5\)。
神奇抽象dp题:记dp[i][j]为完成第i个,A最后用时为j,B的最小用时
显然有三种状态转移:
让A做:dp[i-1][j-t1[i]]
让B做:dp[i-1][j]+t2[i]
让AB做 :dp[i-1][j-t3[i]]+t3[i]
``
但是对于125MB的空间限制,我们显然开不出nnk的数组,我们观察状态转移方程可以发现,dp[i]只能从dp[i-1]转移来,我们可以用滚动数组优化掉
但是对于n个物品,最大容量为 \(n\times5\) 的背包,我们显然不能 \(n\times n\times5\)转移。我们发现有很多转移到背包是空的,每次转移到时候我们只需要在一个范围[L,R]内进行转移
至于L,R的计算:
对于每次转移:
R+=max(t1,t3)
L+=t1 or t3
Code:
const int N=6005;
const int inf=1e9;
using namespace std;
int dp[N*5],t1[N],t2[N],t3[N];
int n,L,R;
void init()
{
for(int i=0;i<N*5;i++){dp[i]=inf;}
}
void work()
{
cin>>n;
for(int i=1;i<=n;i++)
{
scanf("%d%d%d",&t1[i],&t2[i],&t3[i]);
}
init();
dp[0]=0;
for(int i=1;i<=n;i++)
{
R+=max(t1[i],t3[i]);
for(int j=R,A,B,AB;j>=L;j--)
{
A = (t1[i] ? (j-t1[i]>=0 ? dp[j-t1[i]] : inf) : inf);
B = (t2[i] ? dp[j]+t2[i] : inf);
AB= (t3[i] ? (j-t3[i]>=0 ? dp[j-t3[i]]+t3[i] : inf) : inf);
dp[j]=min(AB,min(A,B));
}
L+=(t2[i]|t3[i] ? 0 : t1[i]);
L+=(t1[i]|t2[i] ? 0 : t3[i]);
}
int ans=inf;
for(int i=0;i<=n*5;i++)
{
ans=min(ans,max(i,dp[i]));
}
printf("%d\n",ans);
}
int main()
{
//freopen("P2224.in","r",stdin);freopen("P2224.out","w",stdout);
work();
return 0;
}`

浙公网安备 33010602011771号