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 s 为每件物品所在的组, n u m i num_i numi 为第 i i i 组的物品数量, t t t 为总组数, r e c rec 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) O(nlogn)

a a a 是原序列, n n n 是序列长度, k 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);
  • 1
    点赞
  • 4
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值