牛牛的旅游纪念品 动态规划背包问题

链接:登录—专业IT笔试面试备考平台_牛客网
来源:牛客网
 

题目描述

牛牛在牛市的旅游纪念商店里面挑花了眼,于是简单粗暴的牛牛决定——买最受欢迎的就好了。

但是牛牛的背包有限,他只能在商店的n个物品里面带m个回去,不然就装不下了。

并且牛牛希望买到的纪念品不要太相似,所以导购小姐姐帮助牛牛把纪念品全部排成了一行,牛牛只需要让选出来要买的m个物品中任意两个的位置差都大于等于k就行了。

现在告诉你这n个物品排成一行之后的受欢迎程度(可能是负数),求牛牛带回去的m个物品的最大欢迎度之和。

输入描述:

 

 第一行三个数n,m,k

 接下来一行,有n个整数,是n个物品按顺序的受欢迎程度。

输出描述:

输出一个数为题目所求的最大和

示例1

输入

a4 2 2 2 4 -6 1

4 2 2
2 4 -6 1

输出

5

5

说明

n≤10000,m≤100,m≤nn\leq10000,m\leq100,m\leq nn≤10000,m≤100,m≤n,答案保证在int范围内,保证按照题目要求一定能取到m个物品

这是一道变形的背包问题,多了一个条件也就是选了一个之后那么接下来k-1个是不能选的。

因为必须要装满m个物品,这里一个物品相当于一个体积,以行为体积,列为物品建立二维数组,使用f[i][j]表示恰好装满j体积能够达到的最大价值。还是考虑选还是不选,如果不选那么当前价值就等于上一次装到相同体积价值的最大值也就是f[i-1][j],如果选当前物品,那么就要从第一个到当前物品位置k个之前里面选择最优并装进去(这里1到当前位置前k个的最优实际上已经存储在当前行的前k行这一行中)也就是f[i-k][j-1]+a[i],因此得出方程f[i][j]=max(f[i-1][j],f[i-k][j-1])。

特别的,这里是有正有负的,所以如果不进行初始化,那么如果全是负数就会出现最后全是0的情况,这是不正确的,因此要初始化为负无穷,还有就是对于不到k行的这些行数的初始化处理,这个区间中不可能出现选两个的情况,因而每一行就只需要初始化j=1的一列,也就是最多装一个,取到当前物品能装到的最大价值

下面是程序--->.

#include<stdio.h>
#include<algorithm>
using namespace std;
#define ll long long
#define r(i,a,b) for(int i=a;i<=b;i++)
ll a[10010];
ll f[10010][200];
int main()
{
	int n, m, k; scanf("%d%d%d", &n, &m, &k);
    r(i,1,n)scanf("%lld",a+i);//读入数据
    //初始化,这里因为有正有负,所以必须要初始化负无穷大
	for (int i = 0; i <= n; ++i) 
    {
		for (int j = 0; j <= m; ++j) {
			f[i][j] = -1e9;
		}
	}
	f[1][1] = a[1];
	r(i, 2, k)
		f[i][1] = max(f[i - 1][1], a[i]);
	r(i, k + 1, n) {
		for(int j=m; j>=1; j--)
            //如果j-1被装了东西,那么就可以开始计算装到j个物品后的价值,与之前装到那么j个物品对比
			if (f[i - k][j - 1] != -1e9)
				f[i][j] = max(f[i - 1][j], f[i - k][j - 1] + a[i]);
		f[i][1] = max(f[i-1][1], a[i]);//第一个肯定处理不到,所以特判一次
	}
	printf("%lld\n",f[n][m]);//输出答案
	return 0;
}

  • 2
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 2
    评论
评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值