JZOJ1296.【USACO题库】3.4.4 Raucous Rockers“破锣摇滚”乐队

题目描述

你刚刚继承了流行的“破锣摇滚”乐队录制的尚未发表的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.
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值