“破锣摇滚”乐队 Raucous Rockers——动态规划

“破锣摇滚”乐队 Raucous Rockers



题目来源

洛谷P2736


题目描述

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


解题思路

  • 维护一个二维数组f[i][j],表示在只使用前 i 首歌,总耗时 j 的情况下能够达到的最大的乐曲数目。那么最后只需要将 f[n][t * m] 输出即可(n 表示乐曲总数, t 表示每张唱片的时间, m 表示唱片的个数)
  • 由于同一首歌不能将其从中间分开后放在两个唱片内,因此 f[i][j] 的计算需要考虑以下三种情况:
    • 当不将第 i 首歌放入唱片时 f[i][j] = f[i - 1][j]
    • 当将第 i 首歌放入唱片时需要考虑以下两种情况:
      • 由于每张唱片的时间为 t ,那么通过计算可以得出 j % t 表示的是总时间 j 对应的最后一张不完整的唱片的时间。j / t 表示从时间 j 所包含的完整唱片的个数。
      • 如果第 i 首歌的时间大于 j % t ,说明第 i 首歌可以完整的放入最后一张不完整的唱片,此时 f[i][j] = f[i - 1][j - song[i]] + 1 (song[i] 表示第 i 首歌的时长,下同。)
      • 如果第 i 首歌的时间小于 j % t ,说明第 i 首歌由于时长过长而无法放入最后一张不完整的唱片,因此可以将其放入最后一张 完整的 唱片。此时f[i][j] = f[i - 1[j / t * t - song[i]] + 1
  • 因此总结出状态转移方程:
    jmodtsong[i]
    f[i][j]=max(f[i1][j],f[i1][jsong[i]]+1)

    jmodt<song[i] j÷ttsong[i]0
    f[i][j]=max(f[i1][j],f[i1][j÷ttsong[i]]+1)

源代码


二维数组

#include<iostream>
#include<cstdio>
using namespace std;
int n,t,m;//n首歌   每一张 t 分钟    m 张cd 
int f[25][405];
int song[25];
int main(){
    freopen("in.txt","r",stdin);
    freopen("out.txt","w",stdout);
    cin >> n >> t >> m;
    for(int i = 1;i <= n;i++)
        cin >> song[i];
    for(int i = 1;i <= n;i++) {
        for(int j = 1;j <= t * m;j++){
            f[i][j] = f[i - 1][j];
            if(j % t >= song[i])
                f[i][j] = max(f[i][j],f[i - 1][j - song[i]] + 1);
            else if (j / t * t - song[i] >= 0)
                f[i][j] = max(f[i][j],f[i - 1][j / t * t - song[i]] + 1);
        }
    }
    cout << f[n][t * m];
    return 0;
}

一维滚动数组

#include<iostream>
#include<cstdio>
using namespace std;
int n,t,m;//n首歌   每一张 t 分钟    m 张cd 
int f[405];
int song[25];
int main(){
    freopen("in.txt","r",stdin);
    freopen("out.txt","w",stdout);
    cin >> n >> t >> m;
    for(int i = 1;i <= n;i++)
        cin >> song[i];
    for(int i = 1;i <= n;i++) {
        for(int j = t * m;j >= 1;j--){
            f[j] = f[j];
            if(j % t >= song[i])
                f[j] = max(f[j],f[j - song[i]] + 1);
            else if (j / t * t - song[i] >= 0)
                f[j] = max(f[j],f[j / t * t - song[i]] + 1);
        }
    }
    cout << f[t * m];
    return 0;
}
发布了33 篇原创文章 · 获赞 16 · 访问量 3万+

猜你喜欢

转载自blog.csdn.net/Fine_rose/article/details/72628529