背包DP模型
一开始想到是DP了,也想到状态表示了F[i][j]表示在前i个物品当中选,j个集合。
但是不知道怎么写状态转移方程,也没看出来这其实就是一个01背包模型。
于是就暴力写了个DFS骗了一半分,顺利的TLE了
#include <iostream>
#include <cstring>
#include <algorithm>
using namespace std;
typedef long long LL;
const int N = 10010;
int n, m, k;
LL a[N], sum[N], res;
string s = "1", t = "";
void dfs(int u, LL val)
{
if(u >= k)
{
// cout << val << " ";
res = max(res, val);
return ;
}
if(s.find(t) == -1) return ;
for(int i = 1; i <= n; i ++ )
{
string ss = s.substr(i);
int pos = ss.find(t);
if(pos != -1)
{
pos += i;
// cout << "pos: " << pos << endl;
for(int j = pos; j <= pos + m - 1; j ++ ) s[j] = '1';
dfs(u + 1, val + sum[pos + m - 1] - sum[pos - 1]);
for(int j = pos; j <= pos + m - 1; j ++ ) s[j] = '0';
}
}
}
int main()
{
cin >> n >> m >> k;
for(int i = 1; i <= n; i ++ ) cin >> a[i], sum[i] = sum[i - 1] + a[i];
for(int i = 1; i <= n; i ++ ) s += "0";
for(int i = 1; i <= m; i ++ ) t += "0";
// cout << s << " " << t << endl;
dfs(0, 0);
cout << res << endl;
return 0;
}
看了下别人的代码,这不就是一个01背包模型吗???
物品n对应背包的物品,集合个数k不就是背包的容量吗
难点在于集合中元素的个数m,不同于01背包,但其实也是很好处理的
我们每次只需要选一个集合就好了呀,把一个集合看做一个数,这样k个集合就是选k个数
至于从哪里开始选,我们规定,当前遍历到的物品i,要选的话,他就是该集合的最后一个元素,集合中的其余物品从它的前面选,这样我们就不需要考虑后面的元素了,
#include <iostream>
#include <cstring>
#include <algorithm>
using namespace std;
typedef long long LL;
const int N = 5010;
int n, m, k;
LL dp[N][N], a[N], s[N];
int main()
{
cin >> n >> m >> k;
for(int i = 1; i <= n; i ++ ) cin >> a[i], s[i] = s[i - 1] + a[i];
for(int i = m; i <= n; i ++ )//从m开始,不然Segment Fault,数组下标<0
{
for(int j = 1; j <= k; j ++ )
{
dp[i][j] = dp[i - 1][j]; //不选
dp[i][j] = max(dp[i][j], dp[i - m][j - 1] + (s[i] - s[i - m]));//选就选以当前节点i为最后一个元素的集合
}
}
cout << dp[n][k] << endl;
return 0;
}
大佬的优化代码
# include <bits/stdc++.h>
# define mem(a,b) memset(a,b,sizeof(a))
# define lb(x) ((x) & -(x))
# define pi pair<int,int>
# define X first
# define Y second
# define ABS(x) ((x)>=0?(x):-(x))
# define debug freopen("r.txt","r",stdin)
using namespace std;
typedef long long ll;
ll f[5004];
ll a[5004],s[5004];
int n,m,k;
int main(){
scanf("%d %d %d",&n,&m,&k);
for(int i=1;i<=n;i++)
scanf("%lld",&a[i]);
for(int i=1;i<=n;i++)
s[i]=s[i-1]+a[i];
for(int o=1;o<=k;o++){
for(int j=1;j<=n;j++)
f[j]=max(f[j],f[j-1]);
for(int j=n;j>=m;j--)
f[j]=max(f[j],f[j-m]+s[j]-s[j-m]);
}
printf("%lld\n",*max_element(f+1,f+n+1));
}