背包问题
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]);
混合背包和多重背包只是和上面的变了一下形,就不说了
二维背包
每件物品有两种费用,u 和 v,答案就在两种费用的上限中
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);
}
分组背包
为每件物品所在的组, 为第 组的物品数量, 为总组数, 就是把物品记下来
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]]);
}
}
}
最长上升子序列
可以用二分实现,时间复杂度
是原序列, 是序列长度, 是最长上升子序列的长度
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);
最长公共子序列
两个串分别是 A 和 B,其中 n 是 A 的长度,m 是 B 的长度
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);