P2736 “破锣摇滚”乐队 Raucous Rockers
-
- 150通过
- 350提交
- 题目提供者该用户不存在
- 标签 USACO云端
- 难度 普及+/提高
- 时空限制 1s / 128MB
最新讨论
- 暂时没有讨论
题目描述
你刚刚继承了流行的“破锣摇滚”乐队录制的尚未发表的N(1 <= N <= 20)首歌的版权。你打算从中精选一些歌曲,发行M(1 <= M <= 20)张CD。每一张CD最多可以容纳T(1 <= T <= 20)分钟的音乐,一首歌不能分装在两张CD中。
不巧你是一位古典音乐迷,不懂如何判定这些歌的艺术价值。于是你决定根据以下标准进行选择:
1.歌曲必须按照创作的时间顺序在所有的CD盘上出现。(注:第i张盘的最后一首的创作时间要早于第i+1张盘的第一首)
2.选中的歌曲数目尽可能地多
输入输出格式
输入格式:第一行: 三个整数:N, T, M.
第二行: N个整数,分别表示每首歌的长度,按创作时间顺序排列。
输出格式:一个整数,表示可以装进M张CD盘的乐曲的最大数目。
输入输出样例
输入样例#1:
4 5 2 4 3 4 2
输出样例#1:
3
说明
题目翻译来自NOCOW。
USACO Training Section 3.4
代码
搜索写的
#include<cstdio>
#include<cstdlib>
#include<cstring>
#include<iostream>
#include<cmath>
using namespace std;
int a[27],cd[27],f=1,n,m,t,ans=-1; //a表示每首歌,cd为当前时间,f为使用的第几个CD
void dfs(int pos,int sum){
if(sum+n+1-pos<=ans)return ; //唯一剪枝,假设后面全可以收也不是最优时,就pass
//没有这个1000ms,加了它2ms
if(pos==n+1){
ans=max(ans,sum);
return;
}
//一共就三种方案
if(cd[f]>=a[pos]){ //当前cd直接装上
cd[f]-=a[pos];
dfs(pos+1,sum+1);
cd[f]+=a[pos];
}
if(f<m && t>=a[pos]){ //换一个盘
f++;
cd[f]-=a[pos];
dfs(pos+1,sum+1);
cd[f]+=a[pos];
f--;
}
dfs(pos+1,sum); //直接跳过这个
return ;
}
int main(){
#ifndef ONLINE_JUDGE
freopen("input.in","r",stdin);
freopen("output.out","w",stdout);
#endif
int i,j,k;
scanf("%d%d%d",&n,&t,&m);
for(i=1;i<=m;i++)
cd[i]=t;
for(i=1;i<=n;i++)
scanf("%d",&a[i]);
dfs(1,0);
printf("%d",ans);
return 0;
}
DP写的
#include<cstdio>
#include<iostream>
#include<cstring>
#include<cstdlib>
using namespace std;
int a[110],dp[111][111][111],ans; //dp[i][j][k],i表示放第i首歌
//j表示放入第j个CD,k表示CD剩下的时间
int main(){
#ifndef ONLINE_JUDGE
freopen("input.in","r",stdin);
freopen("output.out","w",stdout);
#endif
int i,j,k,m,n,t;
scanf("%d%d%d",&n,&t,&m);
for(i=1;i<=n;i++)
scanf("%d",&a[i]);
for(i=1;i<=n;i++)
for(j=m;j>=1;j--) //当做01背包搞
for(k=t;k>=a[i];k--){ //每首歌只能放一次,要倒着枚
dp[i][j][k]=dp[i-1][j-1][t]+1;
for(int u=0;u<i;u++)
if(dp[u][j][k-a[i]]+1>dp[i][j][k])
dp[i][j][k]=dp[u][j][k-a[i]]+1; //把前面可以放入的·
}
for(i=1;i<=n;i++)
if(ans<dp[i][m][t])
ans=dp[i][m][t];
printf("%d",ans);
return 0;
}