1. 程式人生 > >usaco P2736 “破鑼搖滾”樂隊 Raucous Rockers(搜尋或類似01的DP)

usaco P2736 “破鑼搖滾”樂隊 Raucous Rockers(搜尋或類似01的DP)

題目描述

你剛剛繼承了流行的“破鑼搖滾”樂隊錄製的尚未發表的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;
}