大致题意
1.从n个物品中选出m个物品,使得值最大
2.任意两个物品之间的位置差 >= k(附加条件)
思路
首先可以看出贪心是不可以的,然后根据求最大值、最小值等关键字眼可以看出这是一道dp题,而且与背包dp板子相似
然后就是dp三件套 定义 初始化 状态转移方程
1.定义 因为最后要求的是从n个物品中选出m个物品,使得值最大,所以就可以定义f[i][j]为从i个物品中选出j个物品的最大值,还有一个附加条件,所以可以再加一维,表示当前第i个物品取不取,因为如果取就要考虑位置差,从前面取,具体可看代码,代码有注释,考虑时间复杂度,n最大是1e4,m最大是1e2,再加q是{0,1},所以不会TLE。故,最终的定义为f[i][j][q] 表示 前i个物品选j个的欢迎度之和最大 q表示选没选第i个物品
2.初始化 因为题中给的值可能为负,所以初始化f数组为INT的最小值,即INT_MIN
3.状态转移方程 上面的理解之后,不理解也可以看代码o.O,具体看代码,代码中注释很详细
#include <bits/stdc++.h>
using namespace std;
#define ll long long
ll f[10010][110][3];//f[i][j][q] 表示 前i个物品选j个的欢迎度之和最大 q表示选没选第i个物品
signed main(){
//输入数据
ll n,m,k;
cin >> n >> m >> k;
vector<ll> a(n+1);
for(ll i = 1 ; i <= n ; ++i) cin >> a[i];
//初始化f数组
for(ll i = 0 ; i <= n ; ++i){
for(ll j = 0 ; j <= m ; ++j){
f[i][j][0] = INT_MIN;
f[i][j][1] = INT_MIN;
}
}
//状态转移方程
f[1][0][0] = 0;
f[1][1][1] = a[1];
for(ll i = 2 ; i <= n ; ++i){
for(ll j = 0 ; j <= m ; ++j){// j == 0 只能不选 j >= 1 才能判断选还是不选
if(j >= 1){// 选物品 可以分为 之前选过 和 之前没选过(j == 1)
f[i][j][0] = max(f[i-1][j][0], f[i-1][j][1]); // 不选物品就直接继承上个状态就可以
if(i - k >= 1) f[i][j][1] = max(f[i - k][j-1][1] + a[i] , f[i - k][j-1][0] + a[i]);// 之前选过就需要考虑位置差 i - k >= 1
else{// 位置差爆了就只能之前不选才可以选这个
if(j == 1) f[i][1][1] = a[i]; // 之前没选过就不用考虑位置差 直接最大值就等于a[i]
}
}
else{
f[i][0][0] = 0;// j == 0 表示没有选物品 只能不选 所以最大值为0
}
}
}
cout << max(f[n][m][1] ,f[n][m][0]) << endl;
return 0;
}