标签:
题目链接:http://codeforces.com/problemset/problem/148/E
题目大意:有n组数据,每次可以从任意一组的两端取出1个数,问你取m个数最大能组成多少?
思路:先将这n组数据变成每组内选i个最大能取到多少,就是合成若干个物品,然后就是分组背包问题。
分组背包:
问题
有N件物品和一个容量为V的背包。第i件物品的费用是c[i],价值是w[i]。这些物品被划分为若干组,每组中的物品互相冲突,最多选一件。求解将哪些物品装入背包可使这些物品的费用总和不超过背包容量,且价值总和最大。
算法
这个问题变成了每组物品有若干种策略:是选择本组的某一件,还是一件都不选。也就是说设f[k][v]表示前k组物品花费费用v能取得的最大权值,则有:
f[k][v]=max{f[k-1][v],f[k-1][v-c[i]]+w[i]|物品i属于组k}
使用一维数组的伪代码如下:
for 所有的组k
for v=V..0
for 所有的i属于组k
f[v]=max{f[v],f[v-c[i]]+w[i]}
注意这里的三层循环的顺序,甚至在本文的第一个beta版中我自己都写错了。“for v=V..0”这一层循环必须在“for 所有的i属于组k”之外。这样才能保证每一组内的物品最多只有一个会被添加到背包中。
另外,显然可以对每组内的物品应用P02中“一个简单有效的优化”。
1 #include <cstdio> 2 #include <cstring> 3 #include <algorithm> 4 #include <vector> 5 #include <map> 6 #include <set> 7 #include <bitset> 8 #include <cmath> 9 #include <numeric> 10 #include <iterator> 11 #include <iostream> 12 #include <cstdlib> 13 #include <functional> 14 #include <queue> 15 #include <stack> 16 #include <list> 17 using namespace std; 18 #define PB push_back 19 #define MP make_pair 20 #define SZ size() 21 #define ST begin() 22 #define ED end() 23 #define CLR clear() 24 #define ZERO(x) memset((x),0,sizeof(x)) 25 typedef long long LL; 26 typedef unsigned long long ULL; 27 typedef pair<int,int> PII; 28 const double EPS = 1e-8; 29 30 const int MAX_N = 111; 31 int n,m; 32 int G[MAX_N][MAX_N]; 33 int a[MAX_N]; 34 int dp[MAX_N*MAX_N]; 35 36 void ProcessMaxSumWithRow(int row,int num){ 37 int SumFront[MAX_N],SumBack[MAX_N]; 38 ZERO(SumFront); 39 ZERO(SumBack); 40 for(int i=1;i<=num;i++){ 41 SumFront[i] = SumFront[i-1] + a[i]; 42 } 43 for(int i=num;i>=1;i--){ 44 SumBack[num-i+1] = SumBack[num-i] + a[i]; 45 } 46 for(int i=1;i<=num;i++){ 47 for(int l=0;l<=i;l++){ 48 int r = i-l; 49 G[row][i] = max(G[row][i],SumFront[l]+SumBack[r]); 50 } 51 } 52 } 53 54 int main(){ 55 scanf("%d%d",&n,&m); 56 for(int i=1;i<=n;i++){ 57 int num; 58 scanf("%d",&G[i][0]); 59 for(int j=1;j<=G[i][0];j++){ 60 scanf("%d",&a[j]); 61 } 62 ProcessMaxSumWithRow(i,G[i][0]); 63 } 64 for(int k=1;k<=n;k++){ 65 for(int v=m;v>=0;v--){ 66 for(int i=1;i<=G[k][0];i++) if(v>=i){ 67 dp[v] = max(dp[v],dp[v-i]+G[k][i]); 68 } 69 } 70 } 71 printf("%d\n",dp[m]); 72 return 0; 73 }
标签:
原文地址:http://www.cnblogs.com/llkpersonal/p/4467827.html