1. 程式人生 > >NOIP模板複習——經典動態規劃

NOIP模板複習——經典動態規劃

揹包問題

0/1 揹包

n 為物品數,m 為揹包體積,v 為物品體積,w 為物品價值,f[i] 為體積為 i 的揹包能獲得的最大價值

for(i=1;i<=n;++i)
{
	scanf("%d%d",&v,&w);
	for(j=m;j>=v;--j)
	    f[j]=max(f[j],f[j-v]+w);
}
printf("%d",f[m]);

完全揹包

for(i=1;i<=n;++i)
{
	scanf("%d%d",&v,&w);
	for(j=v;j<=m;++j)
	    f[j]=max
(f[j],f[j-v]+w); } printf("%d",f[m]);

混合揹包和多重揹包只是和上面的變了一下形,就不說了

二維揹包

每件物品有兩種費用,uv,答案就在兩種費用的上限中

for(i=1;i<=n;++i)
{
	scanf("%d%d%d",&u,&v,&w);
	for(j=x;j>=u;--j)
	    for(k=y;k>=v;--k)
	        f[j][k]=max(f[j][k],f[j-u][k-v]+w);
}

分組揹包

s

s 為每件物品所在的組, n u m i num_i 為第 i
i
組的物品數量, t t 為總組數, r e c rec 就是把物品記下來

for(i=1;i<=n;++i)
{
	scanf("%d%d%d",&v[i],&w[i],&s);
	if(!num[s])  t++;
	rec[s][++num[s]]=i;
}
for(k=1;k<=t;++k)
{
	for(j=m;j>=0;--j)
	{
		for(i=1;i<=num[k];++i)
		{
			if(j<v[rec[k][i]])  continue;
			f[j]=max(f[j],f[j-v[rec[k][i]]]+w[rec[k][i]]);
		}
	}
}

最長上升子序列

可以用二分實現,時間複雜度 O ( n l o g &ThickSpace; n ) O(n*log\;n)

a a 是原序列, n n 是序列長度, k k 是最長上升子序列的長度

d[k=1]=a[1];
for(i=2;i<=n;++i)
{
	if(d[k]<a[i])  d[++k]=a[i];
	else  d[lower_bound(d+1,d+k+1,a[i])-d]=a[i];
}
printf("%d",k);

最長公共子序列

兩個串分別是 AB,其中 nA 的長度,mB 的長度

for(i=1;i<=n;++i)
{
	for(j=1;j<=m;++j)
	{
		if(A[i]==B[j])  f[i][j]=f[i-1][j-1]+1;
		else  f[i][j]=max(f[i-1][j],f[i][j-1]);
	}
}
printf("%d",f[n][m]);

最長公共上升子序列

B[0]=-inf;
for(i=1;i<=n;++i)
{
	if(B[0]<A[i])  num=f[i-1][0];
	for(j=1;j<=m;++j)
	{
		if(A[i]==B[j])  f[i][j]=num+1;
		else  f[i][j]=f[i-1][j];
		if(B[j]<A[i])  num=max(num,f[i-1][j]);
	}
}
int ans=-inf;
for(i=1;i<=m;++i)
    ans=max(ans,f[n][i]);
printf("%d",ans);