洛谷 1417

来源:互联网 发布:超星尔雅刷课软件 编辑:程序博客网 时间:2024/05/29 17:02

      这道题应该可以看出是背包问题,转移方程为f[i][j]=max(f[i-1][j],f[i-1][j-c[i]]+a[i]-j*b[i]),但是如果我们只是这样转移的话会出现问题,这道题与01背包的不同在于每个物品的价值与它放入的顺序有关,因为它的价值是a[i]-j*b[i],怎么办呢?我们考虑一下是否已经存在一种顺序使按照这种顺序装的话价值最大呢?类比与国王游戏那道题,我们考虑一下,假设当前1号在2号前面,此时1号与2号的价值和是a[1]+a[2]-c[1]*b[1]-(c[1]+c[2])*b[2],如果我们交换1号与2号的顺序,可以知道这样是对后面没有影响,那么我们换完以后的价值和是a[1]+a[2]-c[2]*b[2]-(c[1]+c[2])*b[1],如果这次交换能使价值变大,那么我们可以推出c2*b1<c1*b2,这样我们推广一下,如果相邻两个物品出现了这种情况,我们可以把它们交换,这是不是很像冒泡排序?那们我们按照这种方式进行排序最终序列就是确定的了,这样就变成了普通的01背包,但是注意物品的价值仍与剩余体积有关系,因此我们在用滚动数组优化时注意取最优解。

#include<cstdio>#include<cstring>#include<algorithm>using namespace std;#define maxn 100005typedef long long LL;LL f[maxn],ans;int a[55],b[55],c[55],n,m;int main(){scanf("%d%d",&m,&n);for (int i=1;i<=n;i++) scanf("%d",a+i);for (int i=1;i<=n;i++) scanf("%d",b+i);for (int i=1;i<=n;i++) scanf("%d",c+i);for (int i=1;i<=n;i++) for (int j=i+1;j<=n;j++) if ((LL)c[i]*(LL)b[j]>(LL)c[j]*(LL)b[i]) {swap(a[i],a[j]);swap(b[i],b[j]);swap(c[i],c[j]);}for (int i=1;i<=n;i++) for (int j=m;j>=c[i];j--)f[j]=max(f[j],f[j-c[i]]+(LL)a[i]-(LL)j*(LL)b[i]);//printf("%lld\n",f[m]);for (int i=1;i<=m;i++) ans=max(ans,f[i]);printf("%lld\n",ans);return 0;}


0 0