“破鑼搖滾”樂隊 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;
}
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章