codeforces - 148E 题解

题目大意:一个公主有一个摆满瓷器的架子,她生气的时候就要打碎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 }
时间: 2024-10-31 22:57:57

codeforces - 148E 题解的相关文章

codeforces 148E Aragorn&#39;s Story 背包DP

Aragorn's Story Time Limit: 20 Sec  Memory Limit: 256 MB 题目连接 http://codeforces.com/problemset/problem/148/E Description Our protagonist is the handsome human prince Aragorn comes from The Lord of the Rings. One day Aragorn finds a lot of enemies who

CodeForces Dubstep 题解

Vasya works as a DJ in the best Berland nightclub, and he often uses dubstep music in his performance. Recently, he has decided to take a couple of old songs and make dubstep remixes from them. Let's assume that a song consists of some number of word

codeforces Towers 题解

Little Vasya has received a young builder's kit. The kit consists of several wooden bars, the lengths of all of them are known. The bars can be put one on the top of the other if their lengths are the same. Vasya wants to construct the minimal number

codeforces 1296 题解(更新中)

codeforces 1296 题解 A. Array with Odd Sum 想要数组加和为奇数,可以从数组长度是奇数还是偶数着手 若数组长度为偶数,则数组全奇或全偶必定不能构造满足题目要求的数列 若数组长度为奇数,则数组全偶必定不能构造满足题目要求的数列 #include <bits/stdc++.h> using namespace std; typedef long long ll; typedef double db; #define _for(i,a,b) for(int i =

codeforces 1303 题解(更新中)

codeforces 1303 题解 A. Erasing Zeroes 想让字符串中的 \(1\) 连续,而我们能做的只有删 \(0\) ,则需要删去除开头以及结尾外的 所有 \(0\) 块.所以从头扫一遍统计开头 \(0\) 块,从尾扫一遍统计结尾 \(0\) 块,再用 \(0\) 的数量减去这两部分即可,可能为负所以跟 \(0\) 取最大值. 时间复杂度 \(O(n)\) #include <bits/stdc++.h> using namespace std; typedef long

codeforces#536题解

CodeForces#536 A. Lunar New Year and Cross Counting Description: Lunar New Year is approaching, and you bought a matrix with lots of "crosses". This matrix \(M\) of size \(n \times n\) contains only 'X' and '.' (without quotes). The element in t

Codeforces 148E Porcelain (预处理+多重背包)

E. Porcelain time limit per test:3 seconds memory limit per test:256 megabytes During her tantrums the princess usually smashes some collectable porcelain. Every furious shriek is accompanied with one item smashed. The collection of porcelain is arra

CodeForces 281 题解

A题: 题意:给出按照时间顺序的比赛记录,比赛记录了哪一分钟有哪位球员得到了黄牌或红牌,输出罚下的人的序列. 题解:直接按照时间读入模拟就可..注意坑在有可能一位球员罚下后又得到黄牌或红牌,这时候不应再输出这个人了. B题: 题意:给出两个摔跤选手每个动作的得分,正数为第一个人得分负数为第二个人得分,总分高者胜,若相同则“字典序”较大的获胜,再相同则最后得分的人获胜. 题解:直接模拟就可..要用long long.. C题: 题意:两个队伍篮球比赛,给出每个队伍投进的每个球距离球框的距离,现在要

codeforces - 448C 题解

题意:给定一个栅栏,每次涂一行或者一列,问最少几次能够涂完 题解:分治算法+DP思想,每次的状态从竖着涂和横着涂中选择,同时向更高的部分递归计算. 1 #include<iostream> 2 #include<algorithm> 3 #include<cstdio> 4 #include<climits> 5 using namespace std; 6 int a[5001]; 7 int f[5001][5001]; 8 void cal(int l