SSLOJ·KC的瓷器【DP】【前缀和】

SSLOJ 1497 KC的瓷器 porcelain

    • Description--
    • Input--
    • Output--
    • Sample Input--
    • Sample Output--
    • 说明--
    • 解题思路--
    • 代码--

Description–

KC来到了一个盛产瓷器的国度。他来到了一位商人的店铺。在这个店铺中,KC看到了一个有n排的柜子,每排都有一些瓷器,每排不超过100个。那些精美的艺术品使KC一下心动了,决定从N排的商品中买下m个瓷器。

这个商人看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

样例2

9

说明–

1 <= n <= 100
1 <= m <= 10000


解题思路–

预处理fy[ i ][ j ]为第 i 排选 j 个的最大价值 --> f[ i ][ j ]为前 i 排选 j 个的最大价值


代码–

#include 
#include 

using namespace std;

int n, m, a[105], z[105], f[105][10005], q[105][105], fy[105][105];

int main()
{
	scanf("%d%d", &n, &m);
	for (int i = 1; i <= n; ++i)
	{
	    scanf("%d", &a[i]);
	    z[i] = z[i - 1] + a[i]; //前i排一共有z[i]个艺术品
	    for (int j = 1; j <= a[i]; ++j)
	    {
	    	scanf("%d", &q[i][j]);
			if (j > 1) q[i][j] = q[i][j - 1] + q[i][j]; //第i排前j个的价值
	    }
	}
	for (int i = 1; i <= n; ++i) //第i排
	  for (int j = 1; j <= min(m, a[i]); ++j) //选j个
	    for (int k = 0; k <= j; ++k) //左边选k个
	      fy[i][j] = max(fy[i][j], q[i][k] + (q[i][a[i]] - q[i][a[i] - (j - k)]));
	for (int i = 1; i <= n; ++i) //前i排
	  for (int j = 1; j <= min(m, z[i]); ++j) //一共选了j个
	    for (int k = 0; k <= min(j, a[i]); ++k) //第i排选k个
	      f[i][j] = max(f[i][j], f[i - 1][j - k] + fy[i][k]);
	printf("%d", f[n][m]);
	
	return 0;
}

你可能感兴趣的:(前缀和,DP)