dp背包问题(01背包,完全背包,多重背包)

题意: n个物品,v[]表示体积,w[]表示价值,m表示背包容量。求背包可得最大价值

初始化:

若要求为恰好装满,则初始化f[0] = 0,f[1...n] = INT_MIN,求答案时需要遍历最后一行取最大值。

若不要求,则f[0...n] = 0,答案为f[m]。

1.01背包问题

#include<iostream>
#include<algorithm>
using namespace std;
const int N = 1005;
int v[N],w[N];
int f[N][N];
int main()
{
    int n,m;
    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 = 1; j <= m; j ++){
            if(j>=v[i])
                f[i][j] = max(f[i-1][j],f[i-1][j-v[i]]+w[i]); 
            else{
                f[i][j] = f[i-1][j];
            }
        }
    }
    cout<<f[n][m]<<endl;
    return 0;
}

  空间一维优化(第二层循环逆序m....v[i])

#include<iostream>
#include<algorithm>
using namespace std;
const int N = 1005;
int v[N],w[N];
int f[N];
int main()
{
    int n,m;
    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 >= 1 && j>=v[i]; j --){
                f[j] = max(f[j],f[j-v[i]]+w[i]); 
        }
    }
    cout<<f[m]<<endl;
    return 0;
}


 

2.完全背包问题

#include<iostream>
#include<algorithm>
using namespace std;
const int N = 1005;
int v[N],w[N];
int f[N];
int main()
{
    int n,m;
    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 = v[i]; j <=m; j ++){             
                f[j] = max(f[j],f[j-v[i]]+w[i]); 
        }
    }
    cout<<f[m]<<endl;
    return 0;
}

3.多重背包问题

1.朴素做法(01背包变形,复杂度n^3)

#include<iostream>
#include<algorithm>
using namespace std;
const int N = 105;
int v[N],w[N],s[N],f[N];
int main()
{
    int n,m;
    cin>>n>>m;
    for(int i = 1;i <= n;i ++) cin>>v[i]>>w[i]>>s[i];
    for(int i = 1; i <= n; i ++){
        for(int j = m; j >= v[i]; j--){
            for(int k = 1; k * v[i] <= j && k <= s[i]; k ++){
                f[j] = max(f[j],f[j - k * v[i]] + k*w[i]);
            }
        }
    }
    cout<<f[m]<<endl;
    return 0;
}

2.二进制优化

#include<iostream>
#include<algorithm>
#include<vector>
using namespace std;

const int N = 2050;
int f[N];

struct Goods{
  int v,w;
};

int main()
{
    int n,m,v,w,s;
    vector<Goods> goods;
    cin>>n>>m;
    for(int i = 0 ; i < n; i ++){
        cin>>v>>w>>s;
        for(int j = 1 ; j <= s ; j *= 2){
            s -= j;
            goods.push_back({v*j,w*j});
        }
        if(s > 0) goods.push_back({v*s,w*s});
    }
    for(int i = 0 ; i < goods.size(); i ++){
        for(int j = m ;j >= goods[i].v; j-- ){
            f[j] = max(f[j],f[j - goods[i].v] + goods[i].w);
        }
    }
    cout<<f[m]<<endl;
    return 0;
}

4.混合背包问题

tips:先归类为01背包和完全背包,再进行动态规划

s:代表物品种类,若s == -1,为01背包,s == 0,为完全背包,s > 0 ,为多重背包

#include<iostream>
#include<algorithm>
#include<vector>
using namespace std;

const int N = 1010;
int f[N];
struct Goods{
    int s;
    int v,w;
};

int main()
{
    vector<Goods> goods;
    int n,m;
    cin>>n>>m;
    int s,v,w;
    for(int i = 0; i < n; i ++ ){
        cin>>v>>w>>s;
        if(s == -1){
            goods.push_back({-1,v,w});
        }
        else if( s == 0){
            goods.push_back({0,v,w});
        }
        else{
            for(int k = 1 ; k <= s; k *= 2){
                s -= k;
                goods.push_back({-1, k*v,k*w});
            }
            if(s > 0) goods.push_back({-1,s*v,s*w});
        }
    }
    for(int i = 0; i < goods.size(); i ++){
        if(goods[i].s == -1){
            for(int j = m; j >= goods[i].v; j--)   f[j] = max(f[j],f[j - goods[i].v]+goods[i].w);
        }
        else{
            for(int j = goods[i].v ;j <= m; j ++)  f[j] = max(f[j],f[j - goods[i].v]+goods[i].w);
        }
    }
    cout<<f[m]<<endl;
    return 0;
}

5.二维费用的背包问题

f[i][j] 代表体积为i,质量为j的状态的最优解

#include<iostream>
#include<algorithm>
using namespace std;
const int N = 110;
int f[N][N];

int main()
{
    int n,V,M;
    cin>>n>>V>>M;
    for(int i = 0;i < n; i ++){
        int v,m,w;
        cin>>v>>m>>w;
        for(int j = V;j >= v;j --){
            for(int k = M;k >= m; k-- ){
                f[j][k] = max(f[j][k],f[j-v][k-m] + w);
            }
        }
    }
    cout<<f[V][M]<<endl;
    return 0;
}                 

                                                                                                                                      

  • 1
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值