题意:N门课程,有M天时间。【每门课程花费1-M天可以获得的价值不同】,问怎么选择花费在每一门上的课程能获得最大价值,输出最大价值。
思路:分组背包模板题
每一门课程的时间选择都是冲突的,只能选择一个。那么每一门课程就是一个组别,并且天数的选择是冲突的,只能选择一个。就典型的分组背包问题。
第一层循环是枚举每一个组别 k ;第二层循环是背包容量的枚举,j 从V->0;第三层循环是枚举第k个组别的每个物品,如果在j可容纳范围内,就更新当前dp[j]的值为最大{选择该物品,或不选择该物品},就变成是一个01背包问题。
#include <iostream>
#include <algorithm>
#include <cstdio>
#include <cmath>
#include <cstring>
#include <string>
#include <limits>
#include <set>
#include <queue>
#include <vector>
#include <stack>
#include <map>
#define INF 0x3f3f3f3f
#define MID (l + r) >> 1
#define lsn rt << 1
#define rsn rt << 1 | 1
#define Lson lsn, l, mid
#define Rson rsn, mid + 1, r
#define QL Lson, ql, qr
#define QR Rson, ql, qr
#define lowbit(x) x & (-x)
using namespace std;
typedef long long ll;
typedef unsigned long long ull;
const int maxN = 100 + 5;
int N, M;
struct node{
int val, cost;
node(int a = 0, int b = 0): val(a), cost(b) {}
friend bool operator < (node n1, node n2) { return n1.val > n2.val; }
};
int dp[maxN];
vector<node>vt[maxN];
void init()
{
for(int i = 0; i <= N; i ++ )
vt[i].clear();
for(int i = 0; i <= M; i ++ )
dp[i] = 0;
}
int main()
{
while(~scanf("%d%d", &N, &M) && (N || M))
{
init();
for(int i = 1; i <= N; i ++ )
{
for(int j = 1; j <= M; j ++ )
{
int val; scanf("%d", &val);
vt[i].push_back(node(val, j));//花费j得到val的价值
}
}
for(int k = 1; k <= N ; k ++ )//枚举组
for(int j = M; j >= 0; j -- )//背包容量
{
int siz = vt[k].size();
for(int i = 0; i < siz; i ++ )//属于第k组的物品标号
{
if(j >= vt[k][i].cost)
dp[j] = max(dp[j], dp[j - vt[k][i].cost] + vt[k][i].val);
}
}
printf("%d\n", dp[M]);
}
return 0;
}