【NOIP2013模擬】KC的瓷器 多重揹包

Description

KC來到了一個盛產瓷器的國度。他來到了一位商人的店鋪。在這個店鋪中,KC看到了一個有n(1<=n<=100)排的櫃子,每排都有一些瓷器,每排不超過100個。那些精美的藝術品使KC一下心動了,決定從N排的商品中買下m(1<=m<=10000)個瓷器。

這個商人看KC的臉上長滿了痘子,就像苔蘚一樣,跟精美的瓷器相比相差太多,認爲這麼精緻的藝術品被這樣的人買走藝術價值會大打折扣。商人感到不爽,於是規定每次取商品只能取其中一排的最左邊或者最右邊那個,想爲難KC。

現在KC又獲知每個瓷器的價值(用一個不超過100的正整數表示),他希望取出的m個商品的總價值最大。

Input

輸入文件的第一行包括兩個正整數n,m;

接下來2到n+1行,第i行第一個數表示第i排櫃子的商品數量Si,接下來Si個數表示從左到右每個商品的價值。

Output

輸出文件只有一個正整數,即m個商品最大的總價值。

Sample Input

輸入1:

2 3

3 3 7 2

3 4 1 5

輸入2:

1 3

4 4 3 1 2

Sample Output

輸出1:

15

樣例解釋1:

取第一排的最左邊兩個和第二排的最右邊那個。總價直爲3+7+5=15;

輸出2:

9

Data Constraint

對於10%的數據,Si=1,1<=i<=n。

對於另外10%的數據,n=1.

解法:多重揹包

  • 我們設一個數組take[i][j]代表第i排取j個的最大值,如何得到?我們枚舉左邊取k個,那麼右邊取j-k個

  • 然後我們再設一個數組f[i][j]代表前i排取了j個的最大值,很容易得到狀態轉移方程,再套多重揹包板子即可

AC代碼

#include<cstdio>
#define re register int
using namespace std;
int a[105][105],b[105][105];
int n,m,take[105][105],f[105][10005];
inline int read() {
	int x=0,cf=1;
	char ch=getchar();
	while(ch<'0'||ch>'9') {
		if(ch=='-') cf=-1;
		ch=getchar();
	}
	while(ch>='0'&&ch<='9') {
		x=(x<<3)+(x<<1)+(ch^48);
		ch=getchar();
	}
	return x*cf;
}
inline int max(int A,int B) { return A>B?A:B; }
int main() {
	n=read(),m=read();
	for(re i=1;i<=n;i++) {
		b[i][0]=read();
		for(re j=1;j<=b[i][0];j++) {
			b[i][j]=read();
			a[i][j]=a[i][j-1]+b[i][j];
		}
		for(re j=0;j<=b[i][0];j++) {//注意範圍
			for(re k=0;k<=b[i][0];k++) {
				if(j>=k) take[i][j]=max(take[i][j],a[i][k]+a[i][b[i][0]]-a[i][b[i][0]-j+k]);
			}
		}
	}
	for(re i=1;i<=n;i++) {
		for(re j=0;j<=m;j++) {
			for(re k=0;k<=b[i][0];k++) {
				if(j>=k) f[i][j]=max(f[i][j],f[i-1][j-k]+take[i][k]);
			}
		}
	}
	printf("%d",f[n][m]);
	return 0;
}
發佈了75 篇原創文章 · 獲贊 86 · 訪問量 3214
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章