题目描述
你刚刚继承了流行的“破锣摇滚”乐队录制的尚未发表的N(1 <= N <= 20)首歌的版权。你打算从中精选一些歌曲,发行M(1 <= M <= 20)张CD。每一张CD最多可以容纳T(1 <= T <= 20)分钟的音乐,一首歌不能分装在两张CD中。
不巧你是一位古典音乐迷,不懂如何判定这些歌的艺术价值。于是你决定根据以下标准进行选择:
歌曲必须按照创作的时间顺序在CD盘上出现。
选中的歌曲数目尽可能地多。
PROGRAM NAME: rockers
INPUT FORMAT
第一行: 三个整数:N, T, M.
第二行: N个整数,分别表示每首歌的长度,按创作时间顺序排列。
SAMPLE INPUT (file rockers.in)
4 5 2
4 3 4 2
OUTPUT FORMAT
一个整数,表示可以装进M张CD盘的乐曲的最大数目。
SAMPLE OUTPUT (file rockers.out)
3
输入
输出
样例输入
样例输出
数据范围限制
思路:
这题不难,有两种做法
第一种:dfs
很明显,歌和CD的数量都不超过20,2^20的dfs不愁AC不了
dfs应该不用多说吧?能放进就放进,放不进就换一张CD
代码(267ms):
var
a,cd:array[0..400]of longint;
n,m,i,j,t,ans,now:longint;
procedure dfs(x,tot:longint);
begin
if tot+n+1+x<=ans then exit;
if (x>n)or(now>m) then
begin
if tot>ans then ans:=tot;
exit;
end;
if a[x]<=cd[now] then
begin
dec(cd[now],a[x]);
dfs(x+1,tot+1);
inc(cd[now],a[x]);
end;
if (a[x]<=t)and(now<m) then
begin
inc(now);
dec(cd[now],a[x]);
dfs(x+1,tot+1);
inc(cd[now],a[x]);
dec(now);
end;
dfs(x+1,tot);
end;
begin
readln(n,t,m);
for i:=1 to n do read(a[i]);
for i:=1 to m do cd[i]:=t;
now:=1;
dfs(1,0);
writeln(ans);
end.
第二种:DP
我觉得这题数据出小了
如果这道题的数据出到300,dfs一定会TLE
那么就使用DP吧
设f[i,k,j]表示装到第i首曲子,当前这一张CD剩k分钟,已经装进j张CD。
于是对于每首乐曲,我们有三种转移方法:
①直接跳过——f[i-1,k,j]
②在能装入的情况下装入——f[i-1,k-a[i],j]+1
③开一张新CD来装——f[i-1,t-a[i],j+1]+1
最后答案就是f[n,t,m]
代码(0ms):
var
f:array[0..20,0..20,0..20]of longint;
a:array[0..20]of longint;
n,m,i,j,k,t:longint;
function max(x,y:longint):longint;
begin
if x>y then exit(x);
exit(y);
end;
begin
readln(n,t,m);
for i:=1 to n do read(a[i]);
for i:=1 to n do
for j:=1 to m do
for k:=t downto 0 do
begin
f[i,k,j]:=f[i-1,k,j];
if k>=a[i] then f[i,k,j]:=max(f[i,k,j],f[i-1,k-a[i],j]+1);
if (t>=a[i])and(j<>1) then f[i,k,j]:=max(f[i,k,j],f[i-1,t-a[i],j-1]+1);
end;
writeln(f[n,t,m]);
end.