[编程题]01背包
f[ i ][ j ] 表示只看前 i 个物品,总体积是 j 的情况下,总价值最大是多少
result = max{f[ n ][ 0~v ]}
转移方程:
f[ i ][ j ]:
f[ i ][ j ] = max{1. 2.}
#include
#include
#include
using namespace std;
const int N = 1010;
int n,m;
int f[N];
int v[N], w[N];
int main(){
cin >> n >> m;
for(int i=1;i <= n;++i) cin >> v[i] >> w[i];
for(int i=1;i<=n;++i){
// 先循环物品
for(int j=m;j>=v[i];--j){
// 再循环体积
f[j] = max(f[j],f[j-v[i]]+w[i]);
}
}
cout << f[m] << endl;
return 0;
}
#include
#include
#include
using namespace std;
const int N = 1010;
int n,m;
int f[N];
int main(){
cin >> n >> m;
for(int i=0;i<n;i++){
int v,w;
cin >> v >> w;
for(int j = v; j <= m;j++){
f[j] = max(f[j], f[j - v] + w);
}
}
cout << f[m] << endl;
return 0;
}
在状态转移方程处:
01背包是从大到小枚举,完全背包是从下到大枚举。
多重背包问题
/*
f[i] 总体积是i的情况下,最大价值是多少;
for(int i = 0;i < n; i++){
for(int j = 0;j >= v[i];j--){
f[j] = max(f[j],f[j - v[i]] + w[i], f[j - 2 * v[i]] + 2 * w[i]...); // 可以选0个,1个,2个等等 有x+1种选法
}
}
1. f[i] = 0;
f[m]
2. f[0] = 0;f[i] = -INF, i != 0;
*/
#include
#include
#include
using namespace std;
const int N = 110;
int n,m;
int f[N];
int main(){
cin >> n >> m;
for(int i=0;i < n;i++){
int v,w,s;
cin >> v >> w >> s;
for(int j=m;j>=0;j--){
for(int k=1;k<=s && k*v <= j;k++){
f[j] = max(f[j], f[j - k*v] + k*w);
}
}
}
cout << f[m] << endl;
return 0;
}
多重背包问题 II
/*
v,m
log(s)
把s拆成 log(s) 份;
时间复杂度就会降成 1000 * 11 * 2000 = 2 * 10^7 其中11是log(2000)的近似
*/
#include
#include
#include
#include
using namespace std;
const int N = 2010;
int n,m;
int f[N];
struct Good{
int v , w;
};
int main(){
vector<Good> goods;
cin >> n >> m;
for(int i=0;i<n;++i){
int v, w, s;
cin >> v >> w >> s;
for(int k=1 ; k<=s ; k*=2){
s -=k;
goods.push_back({
v*k,w*k});
}
if(s > 0) goods.push_back({
v*s, w*s});
}
for(auto good:goods){
for(int j=m ; j >= good.v;j--){
f[j] = max(f[j], f[j-good.v]+good.w);
}
}
cout << f[m] << endl;
return 0;
}
#include
#include
#include
#include
using namespace std;
const int N = 20010;
int n,m;
int f[N], g[N], q[N];
int main(){
cin >> n >> m;
for(int i=0;i<n;i++){
int c, w, s;
cin >> c >> w >> s;
memcpy(g,f,sizeof f);
for(int j=0;j<c;j++){
int hh =0 ,tt =-1;
for(int k=j;k<=m;k+=c){
f[k] = g[k];
if(hh <= tt && k-s*c > q[hh]) hh++;
if(hh <= tt) f[k] = max(f[k],g[q[hh]] + (k - q[hh])/c*w);
while(hh <= tt && g[q[tt]] - (q[tt] - j) / c*w <= g[k] - (k-j)/c*w) tt--;
q[++tt] = k;
}
}
}
cout << f[m] << endl;
return 0;
}
#include
#include
#include
#include
using namespace std;
const int N = 1010;
int n,m;
int f[N];
struct Thing{
int kind;
int v,w;
};
vector<Thing> things;
int main(){
cin >> n >> m;
for(int i=0;i<n;++i){
int v,w,s;
cin >> v >> w >> s;
if(s < 0) things.push_back({
-1,v,w});
else if(s == 0) things.push_back({
0,v,w});
else{
for(int k=1;k<=s;k*=2){
s-=k;
things.push_back({
-1,v*k,w*k});
}
if(s>0) things.push_back({
-1,v*s,w*s});
}
}
for(auto thing:things){
if(thing.kind < 0){
// 如果是01背包问题从大到小枚举
for(int j=m;j >= thing.v;j--) f[j] = max(f[j],f[j - thing.v] + thing.w);
}else{
// 如果是完全背包问题从小 到大枚举
for(int j=thing.v;j <= m;j++) f[j] = max(f[j],f[j - thing.v] + thing.w);
}
}
cout << f[m] << endl;
return 0;
}
/*
体积是i 重量是j 时价值的最大值
f[i][j]
*/
#include
#include
using namespace std;
const int N = 110;
int n, v, m;
int f[N][N];
int main(){
cin >> n >> v >> m;
for(int i=0;i < n;++i){
int a,b,c;
cin >> a >> b >> c;
for(int j = v; j >=a ;j--){
for(int k = m; k>=b;k--){
f[j][k] = max(f[j][k] , f[j - a][k - b]+c);
}
}
}
cout << f[v][m] << endl;
return 0;
}
#include
#include
#include
using namespace std;
const int N = 110;
int n,m;
int f[N], v[N], w[N];
int main(){
cin >> n >> m;
for(int i=0;i<n;i++){
int s;
cin >> s;
for(int j=0;j<s;j++){
cin >> v[j] >> w[j];
}
for(int j=m;j>=0;j--){
for(int k=0;k<s;++k){
if(j>=v[k])
f[j] = max(f[j],f[j - v[k]] + w[k]);
}
}
}
cout << f[m] << endl;
return 0;
}
#include
#include
#include
using namespace std;
const int N = 1010;
int n,m;
int v[N],w[N],f[N][N];
int main(){
cin >> n >> m;
for(int i=1;i<=n;i++) cin >> v[i] >> w[i];
for(int i=n;i>=1;i--){
for(int j=0;j<=m;j++){
f[i][j] = f[i+1][j];
if(j>=v[i]) f[i][j] = max(f[i][j],f[i+1][j-v[i]]+w[i]);
}
}
int tmp=m;
for(int i=1;i<=n;i++){
if(tmp-v[i]>=0&&f[i][tmp]==f[i+1][tmp-v[i]]+w[i]) {
//tmp-v[i]>=0,只有当前物品能放进去,才比较放与不放的价值大小,如果放不进去,直接下一个物品
cout<<i<<' ';
tmp-=v[i];
}
}
return 0;
}
#include
#include
#include
#include
using namespace std;
const int N = 110;
int n,m;
int h[N], e[N], ne[N], idx; // h是临接表的头,e是edge,ne是next edge
int v[N], w[N], f[N][N];
void add(int a, int b){
e[idx] = b, ne[idx] = h[a], h[a] =idx++;
}
void dfs(int u){
for(int i=h[u];i != -1;i = ne[i]){
int son = e[i];
dfs(son);
for(int j=m-v[u];j>=0;j--)
for(int k=0;k<=j;k++)
f[u][j] = max(f[u][j],f[u][j-k]+f[son][k]);
}
for(int i=m;i >= v[u];i--) f[u][i] = f[u][i - v[u]] + w[u];
for(int i=0;i < v[u];i++) f[u][i] = 0;
}
int main(){
memset(h,-1,sizeof h);
cin >> n >> m;
int root;
for(int i=1;i<=n;++i){
int p;
cin >> v[i] >> w[i] >> p;
if(p == -1) root = i;
else add(p,i);
}
dfs(root);
cout << f[root][m] << endl;
return 0;
}