有 n 种物品要放到一个袋子里,袋子的总容量为 m。第 i 个物品属于第 ai 组,每组物品我们只能从中选择一个。第 i 种物品的体积为 vi,把它放进袋子里会获得 wi 的收益。问如何选择物品,使得在物品的总体积不超过 m 的情况下,获得最大的收益?请求出最大收益。
输入格式: 第一行两个整数 n,m。接下来 n行,每行三个整数 ai,vi,wi。
输出格式: 一个整数,表示答案。
数据规模; 对于所有数据,保证 1≤n,m,ai,vi,wi≤1000。
核心思想是利用vector将同组的数据存放在一起。需要注意在后面循环的时候,外层循环的 i 指的是组数而不是01背包问题里面的物品序号。
#include<bits/stdc++.h>usingnamespace std;int n, m, f[1001], v[1001], w[1001], a[1001];
vector<int>c[1001];intmain(){scanf("%d%d",&n,&m);for(int i =1; i <= n; i++){scanf("%d%d%d",&a[i],&v[i],&w[i]);
c[a[i]].push_back(i);;}for(int i =1; i <=1000; i++)for(int j = m; j ; j--)for(auto k: c[i])if(v[k]<= j)
f[j]=max(f[j], f[j - v[k]]+ w[k]);printf("%d", f[m]);}
二维背包
有 n 种物品要放到一个袋子里,袋子的总容量为 m,我们一共有 k 点体力值。第 i 种物品的体积为 vi,把它放进袋子里会获得 wi 的收益,并且消耗我们 ti 点体力值,每种物品只能取一次。问如何选择物品,使得在物品的总体积不超过 m 并且花费总体力不超过 k 的情况下,获得最大的收益?请求出最大收益。
输入格式: 第一行三个整数 n,m,k。接下来 n行,每行三个整数 vi,wi,ti。
输出格式: 一个整数,表示答案。
数据规模; 对于所有数据,保证 1≤n,m,ai,vi,wi≤100。
#include<bits/stdc++.h>usingnamespace std;int n, m, k, f[101][101], v[101], w[101], t[101];intmain(){scanf("%d%d%d",&n,&m,&k);for(int i =1; i <= n; i++)scanf("%d%d%d",&v[i],&w[i],&t[i]);for(int i =1; i <= n; i++)for(int j = m; j >= v[i]; j--)for(int x = k; x >= t[i]; x--)
f[j][x]=max(f[j][x], f[j - v[i]][ x - t[i]]+ w[i]);printf("%d", f[m][k]);}
多重背包3*
有 n 种物品要放到一个袋子里,袋子的总容量为 m,第 i 种物品的体积为 vi,把它放进袋子里会获得 wi 的收益,一共有 li 个。问如何选择物品,使得在物品的总体积不超过 m 的情况下,获得最大的收益?请求出最大收益。
输入格式 第一行两个整数 n,m。 接下来 n行,每行两个整数 vi,wi。
输出格式 一个整数,表示答案
数据规模 对于所有数据,保证 1≤n,m,vi,wi, li≤ 10000。
先将数据按照mod vi 分类后再使用单调队列进行排序。
#include<bits/stdc++.h>usingnamespace std;int n, m, v, l, w, p, x, c[10001][2], f[10001];intmain(){scanf("%d%d",&n,&m);for(int i =1; i <= n; i++){scanf("%d%d%d",&v,&w,&l);for(int j =0; j < v; j++){int h =1, t =0;for(p = j, x =1; p <= m; p += v,++x){int e = f[p]- x * w, r = x + l;for(; t >= h && e >= c[t][1];--t);
c[++t][0]= r; c[t][1]= e;
f[p]= c[h][1]+ x * w;for(; t >= h && c[h][0]== x;++h);}}}printf("%d", f[m]);}