[BZOJ1222/Luogu2224][HNOI2001]产品加工
题目链接:
题号不错
这种类型的\(DP\)是第二次见了,不过第一次是刚学的时候了,现在早就忘了,思想还是很神的。
看到时间\(\le 5\)也能猜到很重要了。
设\(f_{[i],[j]}\)表示前\(i\)件物品,\(A\)机器用时\(j\)秒时\(B\)机器最短用时。
为了避免分类讨论,如果\(a,b,c\)为\(0\)则改成\(+\infty\)
那么有如下转移方程式:
\[f_{[i],[j]}=
\begin{cases}
f_{[i-1],[j-a]} & (a\le j)\\
f_{[i-1],[j]}+b\\
f_{[i-1],[j-c]}+c &(c\le j)
\end{cases}
\]
为什么不用考虑顺序?
因为对于所有空隙,一定可以通过适当的调整来拼在一起,保证答案的正确性。
这题还需要一定的毒瘤常数优化。
#include <cstdio>
#include <cstring>
inline int Min(int a,int b){return a<b?a:b;}
inline int Max(int a,int b){return a>b?a:b;}
const int Inf=0x3f3f3f3f;
int n,Ans=Inf,Up;
int f[30015];
int main()
{
scanf("%d",&n);
memset(f,0x3f,sizeof f),f[0]=0;
for(register int a,b,c;n--;)
{
scanf("%d%d%d",&a,&b,&c);
Up+=Max(a,c);
a?0:a=Inf;
b?0:b=Inf;
c?0:c=Inf;
for(register int i=Up;i>=0;--i)
{
b==Inf?f[i]=Inf:f[i]+=b;
if(a<=i)f[i]=Min(f[i],f[i-a]);
if(c<=i)f[i]=Min(f[i],f[i-c]+c);
}
}
for(int i=0;i<=Up;++i)
Ans=Min(Ans,Max(i,f[i]));
printf("%d\n",Ans);
return 0;
}