题目大意:一个公主有一个摆满瓷器的架子,她生气的时候就要打碎m个瓷器。这个架子有n层,每层的瓷器每次只能从最左边拿或者从最右边拿,问打碎的瓷器的最大价值。
题解:这是一个分组背包的DP,首先将每一层上拿出瓷器的方案作为一个物品,拿出瓷器的方案的代价是瓷器数量,价值是这一层上所有方案中最大的价值。
首先为了计算方案的时候可以快速计算,我们在读入的时候就计算出前缀和sum,然后在计算方案的时候,每一层上打碎的数量对应一个物品,然后枚举总数量分配到两侧打碎的价格,得到最大价值。最后使用分组背包解决。
分组背包常见代码:
K代表有K个组,V是背包最大容量,这里要注意在最里面要防止v-ci小于0,否则会出现未定义行为,导致计算错误
for k 1 to K for v V to 0 for all item i in group k
F[v]=max(F [v], F [v - Ci] + Wi);
1 #include<iostream>
2 #include<cstdio>
3 #include<algorithm>
4 #include<cstring>
5 #include<vector>
6 using namespace std;
7 struct datatype
8 {
9 int value;
10 int space;
11 };
12 vector<datatype> a[101];
13 int shelf[101][101];
14 int sum[101][101];
15 int amount[101];
16 int f[10001];
17 int main()
18 {
19 int n,m;
20 scanf("%d%d",&n,&m);
21 memset(sum,0,sizeof(sum));
22 for(int i=1;i<=n;i++)
23 {
24 int x;
25 scanf("%d",&x);
26 amount[i]=x;
27 for(int j=1;j<=x;j++)
28 {
29 scanf("%d",&shelf[i][j]);
30 sum[i][j]=sum[i][j-1]+shelf[i][j];
31 }
32 }
33 for(int i=1;i<=n;i++)
34 {
35 for(int k=1;k<=amount[i];k++)
36 {
37 datatype tmp;
38 tmp.space=k;
39 tmp.value=0;
40 for(int j=0;j<=k;j++)
41 {
42 int tmp_v=0;
43 tmp_v+=sum[i][j];
44 tmp_v+=sum[i][amount[i]]-sum[i][amount[i]-(k-j)];
45 tmp.value=max(tmp_v,tmp.value);
46 }
47 a[i].push_back(tmp);
48 }
49 }
50 memset(f,0,sizeof(f));
51 for(int i=1;i<=n;i++)
52 {
53 for(int j=m;j>=0;j--)
54 {
55 vector<datatype>::iterator it;
56 for(it=a[i].begin();it!=a[i].end();it++)
57 {
58 if(j-(*it).space<0)
59 {
60 continue;
61 }
62 f[j]=max(f[j],f[j-(*it).space]+(*it).value);
63 }
64 }
65 }
66 printf("%d\n",f[m]);
67 return 0;
68 }