缘起
学习分组背包~ hdu 1712 ACboy needs your help
分析
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30
| 现在acboy有m天的时间来修n门课程,然后给你一个矩阵, A[i][j]表示花j天的时间学习第i门课程能够得到A[i][j]学分, 我们的任务是把acboy所拥有的天数m天分成一些部分来学习这其中的课程,使得能够在学校课程当中收获学分最多。
【输入】 多样例. 每个样例开始于 n和m, 然后是一个n*m矩阵.A[i][j], (1<=i<=N<=100,1<=j<=M<=100) 最后以两个0结尾
【输出】 对每个样例,输出最大收益
【样例输入】 2 2 1 2 1 3 2 2 2 1 2 1 2 3 3 2 1 3 2 1 0 0
【样例输出】 3 4 6
【限制】 1s
|
本题是经典的分组背包问题. 首先讲清楚分组背包问题
1 2
| 分组背包问题是N件物品,背包容量是V,第i件物品的重量是W[i],价值是P[i],这些物品分成K组 组内物品互斥,也就是不能共存于背包中(也就是每组物品中最多取一件),问背包的最大价值
|
这个问题变成了每组物品有若干种策略:是选择本组的某一件,还是一件都不选。也就是说设F [k, v]表示前k组物品花费费用v能取得的最大权值,则有
1
| F[k,v] = max{F[k-1, v], F[k-1,v-Ci]+Wi | item i 属于 group k}
|
使用伪代码写分组背包的算法模板也很简单
1 2 3 4 5
| def function gp: for k = 1...K for v = V,..,0 for item i in group k F[v] = max{F[v], F[v-Ci]+Wi}
|
之所以上面 for v = V,..,0, 能到0是因为一组物品完全可以不取任何一件. 分组的背包问题将彼此互斥的若干物品称为一个组,这建立了一个很好的模型。
回到本题分组背包就要找到互斥的物品才行. 然后将这些物品归为物品组.
本题的物品是 (共计m*n 件物品)
第1门课花费1天学,第1门课花费2天学,….,第1门课程花费m-1天学习, 第1门课程花费m天学习.
第2门课花费1天学,第2门课花费2天学,….,第2门课程花费m-1天学习, 第2门课程花费m天学习.
… …
第n-1门课花费1天学,第n-1门课花费2天学,….,第n-1门课程花费m-1天学习, 第n-1门课程花费m天学习.
第n门课花费1天学,第n门课花费2天学,….,第n门课程花费m-1天学习, 第n门课程花费m天学习.
而每行的m个物品归为一组, 而且互斥(即一门课程你决定使用x天学习就不能使用y天学习),共计n组. 这样就是一个分组背包问题了. 然后背包容量显然就是天数——即你要从上面n个组中每组中至多选择一个物品, 使得消耗的天数总和<=m.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48
| //#include "stdafx.h" #include <stdio.h> #include <string.h> #include <algorithm> using namespace std; //#define LOCAL
const int maxn = 105; int n,m, a[maxn][maxn], dp[maxn];
void gp() // 分组背包 { memset(dp,0,sizeof(dp)); // 不选任何一组, 则显然学分是0 for (int k = 1; k<=n; k++) // 逐个考察前k组 { for (int v = m; ~v; v--) // 背包容量为m, 用第k个物品组中的物品来进行01背包 { for (int i = 1;i<=m;i++) { if (v>=i) { dp[v] = max(dp[v], dp[v-i]+a[k][i]); // 第k组的第i件物品消耗i(即决定花费i天学习第k门课程) } } } } }
int main() { #ifdef LOCAL freopen("d:\\data.in", "r", stdin); // freopen("d:\\my.out", "w", stdout); #endif while(scanf(" { for (int i = 1;i<=n; i++) { for (int j = 1;j<=m;j++) { scanf(" } } gp(); printf(" } return 0; }
|
ac情况
Status |
Accepted |
Time |
93ms |
Memory |
1776kB |
Length |
738 |
Lang |
C++ |
Submitted |
2019-10-25 17:54:19 |
Shared |
|
RemoteRunId |
31093222 |