usaco P2736 “破鑼搖滾”樂隊 Raucous Rockers(搜尋或類似01的DP)
阿新 • • 發佈:2019-01-28
題目描述
你剛剛繼承了流行的“破鑼搖滾”樂隊錄製的尚未發表的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; }