题目如下:
你刚刚得到了流行的“破锣摇滚”乐队录制的尚未发表的N(1 <= N <=20)首歌的版权。你打算从中精选一些歌曲,发行M(1 <= M <= 20)张CD。每一张CD最多可以容纳T(1 <= T <=20)分钟的音乐,一首歌不能分装在两张CD中。
不巧你是一位古典音乐迷,不懂如何判定这些歌的艺术价值。于是你决定根据以下标准进行选择:
歌曲必须按照创作的时间顺序在CD盘上出现。
选中的歌曲数目尽可能地多。
INPUTFORMAT
第一行:三个整数:N, T, M.
第二行:N个整数,分别表示每首歌的长度,按创作时间顺序排列。
SAMPLEINPUT (file rockers.in)
4 5 2
4 3 4 2
OUTPUTFORMAT
一个整数,表示可以装进M张CD盘的乐曲的最大数目。
SAMPLEOUTPUT (file rockers.out)
3
我的方法就是设f[i][j][k]表示在前i张唱片、录到第j分钟、录到第k首歌所录得最多歌曲数,转移方程如下:
f[i][j][k]=max{前一分钟的歌曲数,前一首歌的歌曲数,把第k首歌在当前位置放进去的歌曲数(如果可以)}
然后因为每张唱片的时间一样,所以可以这样简化:
设f[i,j]表示在前i首歌中,共录到第j分钟所录得最多歌曲数
f[k,i*t+j]:=max{f[k,i*t+j-1], 前一分钟的歌曲数,
f[k-1,i*t+j], 前一首歌的歌曲数
f[k-1,i*t+j-len[k]]+1(len[k]<=j) } 把第k首歌在当前位置放进去的歌曲数
代码如下:
01 /*
02 ID:xpycc1
03 PROG:rockers
04 LANG:C++
05 */
06
07 #include<fstream>
08 #define MAXN 20
09 #define MAXM 20
10 #define MAXT 20
11 using namespace std;
12
13 ifstream fin("rockers.in");
14 ofstream fout("rockers.out");
15
16 int f[MAXM+1][MAXT+1][MAXN+1],len[MAXN+1],n,m,t;
17
18 int main(){
19 int i,j,k;
20 fin>>n>>t>>m;
21 for(i=1;i<=n;++i)
22 fin>>len[i];
23
24 for(i=1;i<=m;++i) //第i张唱片
25 for(j=1;j<=t;++j) //第j分钟
26 for(k=1;k<=n;++k){ //第k首歌
27 if(j==1) //换唱片
28 f[i][j][k]=max(f[i][j][k-1], //前一首歌的歌曲数
29 f[i-1][t][k]); //前一分钟的歌曲数(下同)
30 else //没有换唱片
31 f[i][j][k]=max(f[i][j][k-1], f[i][j-1][k]);
32
33 if(len[k]<j) //没有换唱片
34 f[i][j][k]=max(f[i][j][k],
35 f[i][j-len[k]][k-1]+1);//把第k首歌在当前位置放进去的歌曲数(下同)
36 if(len[k]==j) //换唱片
37 f[i][j][k]=max(f[i][j][k], f[i-1][t][k-1]+1);
38 }
39
40 fout<<f[m][t][n]<<endl;
41 return 0;
42 }