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

题目链接:

BZOJ1222

Luogu2224

题号不错

这种类型的(DP)是第二次见了,不过第一次是刚学的时候了,现在早就忘了,思想还是很神的。

看到时间(le 5)也能猜到很重要了。

(f_{[i],[j]})表示前(i)件物品,(A)机器用时(j)秒时(B)机器最短用时。

为了避免分类讨论,如果(a,b,c)(0)则改成(+infty)

那么有如下转移方程式:

[f_{[i],[j]}= egin{cases} f_{[i-1],[j-a]} & (ale j)\ f_{[i-1],[j]}+b\ f_{[i-1],[j-c]}+c &(cle 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
",Ans);
	return 0;
}
原文地址:https://www.cnblogs.com/LanrTabe/p/10184799.html