洛谷 1417

Posted TSOI_Vergil

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了洛谷 1417相关的知识,希望对你有一定的参考价值。

      这道题应该可以看出是背包问题,转移方程为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 100005
typedef 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;	


以上是关于洛谷 1417的主要内容,如果未能解决你的问题,请参考以下文章

洛谷 1417

洛谷P1080 国王游戏

洛谷 P1080 国王游戏

洛谷 P2799 国王的魔镜

洛谷——P2799 国王的魔镜

[NOIP2012] 提高组 洛谷P1080 国王游戏