题目来源:
https://www.luogu.org/problemnew/show/P2736
题目描述:
题目描述
你刚刚继承了流行的“破锣摇滚”乐队录制的尚未发表的N(1 <= N <= 20)首歌的版权。你打算从中精选一些歌曲,发行M(1 <= M <= 20)张CD。每一张CD最多可以容纳T(1 <= T <= 20)分钟的音乐,一首歌不能分装在两张CD中。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
解题思路:
这题就是直接搜就行,不过要考虑剪枝,就是把目前的答案+剩下的所有歌<=ans就可以return了。
我们用dfs(int id,int num,int sum,int rec)
id表示当前的歌曲号,num表示盘的号码,sum表示当前盘剩余,rec已经录的歌数
我们可以用这张盘,dfs(id+1,num,sum-a[id],rec+1);
不用这张盘 dfs(id,num+1,t,rec);
不录这歌 dfs(id+1,num,sum,rec);
刚好录满这盘 dfs(id+1,num+1,t,rec+1);
然后就行了。。。
代码:
#include <iostream>
#include <iomanip>
#include <cstdio>
#include <cstring>
#include <string>
#include <vector>
#include <map>
#include <algorithm>
#include <queue>
#include <stack>
#include <cmath>
#define inf 0x3f3f3f3f
#define ll long long
using namespace std;
const int maxn=1e5+10;
int a[30],n,t,m,ans=0;
void dfs(int id,int num,int sum,int rec)
{
if(rec+n-id+1<=ans)return ;
if(num>m||id>n)
{
if(rec>ans)ans=rec;
return ;
}
if(sum>a[id])dfs(id+1,num,sum-a[id],rec+1);
else if(sum==a[id])dfs(id+1,num+1,t,rec+1);
dfs(id,num+1,t,rec);
dfs(id+1,num,sum,rec);
}
int main()
{
scanf("%d%d%d",&n,&t,&m);
for(int i=1;i<=n;i++)
scanf("%d",&a[i]);
dfs(1,1,t,0);
printf("%d\n",ans);
return 0;
}