[BZOJ1222/Luogu2224][HNOI2001]产品加工

题目链接:

BZOJ1222

Luogu2224

题号不错

这种类型的\(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;
}
posted @ 2018-12-27 14:33  LanrTabe  阅读(208)  评论(0编辑  收藏  举报