Description
从T组物品中选出一些物品,放入背包中,求剩余空间的最小值。
限制条件:从每组物品中挑选物品必须要选取连续的一段。就是说,如果这组物品共有n个: 物品1、物品2、物品3、…、物品n,那么只能选取物品i、物品i+1、…、物品j,其中1<=i<=j<=n,或者不选。
Input
第一行为两个用空格隔开的正整数v和T。表示背包的空间和物品的组数。接下来有T行,每行先是一个正整数ni,表示这组物品有ni个,然后ni个正整数,表示每个物品的大小。
Output
仅一个数,表示剩余空间的最小值。
Sample Input
100 3
3 7 6 8
2 80 70
4 101 108 103 150
Sample Output
6
Data Constraint
Hint
【样例说明】
第1组选6、8,第2组选80,第3组不选。
【限制】
60%的数据满足:1 <= ni <= 10
100%的数据满足:1 <= ni <= 100,1<=v<=5000,1<=T<=10
思路:
这题比较经典,可以列入背包问题的例题
之前有一段时间没做背包,比赛时推了十分钟左右,然后开码
从一开始就在思考DP的做法
题目中限制的取法,只需再加上两个l,r循环枚举头尾
那么思考状态
一个状态明显不能满足要求(背包容量的状态)
于是乎,我们可以考虑加上另一个第几层的状态:
f[i,j]表示到取到第j层时容量为i的背包装入的最大值
转移方程为f[i,j]=max(f[i,j],f[i-x,j-1]+x)
无需任何初始化
这里的x为当前这一段物品要取的和,用前缀和求即可(x=pre[j,r]-pre[j,l-1])
然后AC
简单吧?
哦,对了,还有一个东西
我们可以在DP之前先把每一层的所有情况的数字存到另一个数组里
DP中使用一重循环代替枚举头尾l,r的两重循环
由此可以将四重循环压至三重
code好看了,时间也砍了100ms左右
代码:
var
f:array[0..5000,0..10]of longint;
pre:array[0..10,0..100]of longint;
fx:array[0..10,0..100000]of longint;
a,b:array[0..10]of longint;
n,i,j,k,l,r,v,t,tot,ans,x:longint;
function max(x,y:longint):longint;
begin
if x>y then exit(x);
exit(y);
end;
function min(x,y:longint):longint;
begin
if x<y then exit(x);
exit(y);
end;
begin
readln(v,t);
for i:=1 to t do
begin
read(a[i]);
for j:=1 to a[i] do
begin
read(x);
pre[i,j]:=pre[i,j-1]+x;
end;
end;
for i:=1 to t do
for l:=1 to a[i] do
for r:=l to a[i] do
begin
inc(b[i]);
fx[i,b[i]]:=pre[i,r]-pre[i,l-1];
end;
for i:=1 to v do
for j:=1 to t do
begin
f[i,j]:=f[i,j-1];
for k:=1 to b[j] do
begin
if fx[j,k]<=i then
f[i,j]:=max(f[i,j],f[i-fx[j,k],j-1]+fx[j,k]);
end;
end;
for i:=1 to t do
ans:=max(ans,f[v,i]);
writeln(v-ans);
end.

本文介绍了一种经典的背包问题解法,通过对每组物品选择连续段进行优化,利用动态规划减少时间复杂度,并通过预处理简化计算过程。
765

被折叠的 条评论
为什么被折叠?



